<?php

namespace common\service;

use common\exception\LogicException;
use common\exception\ReviewFeedbackPermissionException;
use common\model\CosMediaModel;
use common\model\DelayOrderTaskModel;
use common\model\EntityModel;
use common\model\ModuleModel;
use common\model\NoteEntityRelationModel;
use common\model\NoteModel;
use common\model\NoteRecordModel;
use common\model\ProjectStepCategoryConfirmConfigModel;
use common\model\RelationNoteEntityRelationModel;
use common\model\ReviewFeedbackConfirmModel;
use common\model\ReviewFeedbackEntityModel;
use common\model\ReviewFeedbackModel;
use common\model\ProjectModel;
use common\model\StageModel;
use common\model\TagRelationModel;
use common\model\TaskModel;
use common\model\UserModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\exception\HttpResponseException;
use think\Hook;
use think\Model;
use think\model\RelationModel;
use think\module\Module;
use Throwable;
use Webman\Stomp\Client;

class DemandOrderService
{
    use SingletonTrait;

    const APPEND_MARK = 1; // 新增标识(有此标识需要校验提出阶段规则)

    protected $allowPublishSaveFields = [
        'review_feedback_entity_hair_making',
        'review_feedback_entity_production_method',
        'review_feedback_entity_cloth_solution',
        'review_feedback_entity_fx',
        'review_feedback_entity_comp_type',
        'review_feedback_entity_fx_production',
        'review_feedback_entity_draft_data',
    ];

    private $reviewFeedbackModel;

    public function __construct()
    {
        $this->reviewFeedbackModel = model(ReviewFeedbackModel::class);
    }

    /**
     * 创建、 更新需求单
     * @param $data
     * @return array|bool|null
     * @throws Throwable
     * @throws Exception
     */
    public function save($data)
    {
        $orderId = date("YmdHis", time()) . sprintf("%03d", rand(0, 999));
        if (isset($data['demand_order']['step_category_ids']) && is_array($data['demand_order']['step_category_ids'])) {
            $data['demand_order']['step_category_ids'] = implode(',', $data['demand_order']['step_category_ids']);
        }

        $reviewFeedbackModel = model(ReviewFeedbackModel::class);
        $reviewFeedbackModel->setCurrentModuleCode('review_feedback');
        $reviewFeedbackModule = module_by_code('review_feedback');
        $currentModuleLinkRelation = $reviewFeedbackModel->parserFilterModuleRelation(true);
        $relationIds = [];

        $reviewFeedbackModel->startTrans();
        try {
            if (empty($data["demand_order"]["id"])) {
                //新增
                if ($data["demand_order"]["demand_type"] == "demand_order") {
                    $data['demand_order']['demand_order_id'] = $orderId;
                    // 组装阶段信息和新增类型
                    $this->buildStageAndStandardAppend($data['demand_order'], $data['demand_order']['project_id'], $data['demand_order']['episode_codes'], $data['demand_order']['stage_id']);
                }
                if ($data["demand_order"]["demand_type"] == "review_feedback") {
                    foreach ($data as $moduleCode => $item) {
                        // 获取请求中的 cos_media
                        if (isset($currentModuleLinkRelation[$moduleCode]) && $currentModuleLinkRelation[$moduleCode]['module_code'] === 'cos_media') {
                            $mediaIds = [];

                            if (is_many_dimension_array($item)) {
                                foreach ($item as $mediaItem) {
                                    if (empty($mediaItem)) {
                                        continue;
                                    }

                                    $mediaData = CosMediaService::getInstance()->findAddMedia($mediaItem);
                                    if (!$mediaData) {
                                        throw new LogicException(model(CosMediaModel::class)->getError(), ErrorCode::MEDIA_ADD_FAILURE);
                                    } else {
                                        if (!in_array($mediaData['id'], $mediaIds)) {
                                            $mediaIds[] = $mediaData['id'];
                                        }
                                    }
                                }
                            }
                            $relationIds[$moduleCode] = join(',', $mediaIds);
                        }
                    }

                    foreach ($relationIds as $filed => $relationId) {
                        $data['demand_order'][$filed] = $relationId;
                    }
                }

                $commonService = CommonService::instance("review_feedback");
                $resData = $commonService->commonCreate(['data' => $data['demand_order']], $reviewFeedbackModule);
            } else {
                $demandOrderItem = model(ReviewFeedbackModel::class)->find($data["demand_order"]['id']);
                if (empty($demandOrderItem)) {
                    throw new LogicException("demand order not exist", ErrorCode::DEMAND_ORDER_NOT_EXIST);
                }

                if ($demandOrderItem["demand_type"] == "demand_order") {
                    // 组装阶段信息和新增类型
                    if (!empty($data['demand_order']['stage_id'])) {
                        $this->buildStageAndStandardAppend($data['demand_order'], $data['demand_order']['project_id'], $data['demand_order']['episode_codes'], $data['demand_order']['stage_id'], $data['demand_order']['id']);
                    }
                }

                if ($demandOrderItem["demand_type"] == "review_feedback") {
                    foreach ($data as $moduleCode => $item) {
                        // 获取请求中的 cos_media
                        if (isset($currentModuleLinkRelation[$moduleCode]) && $currentModuleLinkRelation[$moduleCode]['module_code'] === 'cos_media') {
                            $mediaIds = [];
                            if (is_many_dimension_array($item)) {
                                foreach ($item as $mediaItem) {
                                    if (empty($mediaItem)) {
                                        continue;
                                    }
                                    // 判定是否需要更新
                                    if (!empty($mediaItem["id"])) {
                                        $mediaIds[] = $mediaItem["id"];
                                        if (!empty($mediaItem['param'])) {
                                            CosMediaService::getInstance()->findAddMedia($mediaItem);
                                        }
                                    } else {
                                        $mediaData = CosMediaService::getInstance()->findAddMedia($mediaItem);
                                        if (!in_array($mediaData['id'], $mediaIds)) {
                                            $mediaIds[] = $mediaData['id'];
                                        }
                                    }
                                }
                            }
                            $relationIds[$moduleCode] = join(',', $mediaIds);
                        }
                    }

                    // 把水平自定义关联数据回插入主表
                    foreach ($relationIds as $filed => $relationId) {
                        $data['demand_order'][$filed] = $relationId;
                    }
                }
                $commonService = CommonService::instance("review_feedback");
                $resData = $commonService->commonUpdate(['data' => $data['demand_order']], $reviewFeedbackModule, false);
            }

            $reviewFeedbackModel->commit();
            return $resData;
        } catch (Throwable $e) {
            $reviewFeedbackModel->rollback();
            throw $e;
        }
    }

    /**
     * 获取需求单列表
     * @param $param
     * @return array
     * @throws Exception
     */
    public function getDemandOrderList($param)
    {
        $reviewFeedbackModel = $this->reviewFeedbackModel;
        $page = $param["page"] ?? [1, config("default_page_total")];
        $fields = $param["fields"] ?? "";
        if (!empty($param['filter']['project_id'])) {
            $project = model(ProjectModel::class)->find($param['filter']['project_id']);
            if (!empty($project['belong_project_id'])) {
                $param['filter']['project_id'] = $project['belong_project_id'];
            }
        }

        $filter = $param["filter"] ?? [];
        $episodeCodes = $param['filter']['episode_codes'] ?? [];
        unset($param['filter']['episode_codes']);
        unset($filter['episode_codes']);

        if (!empty($param['need_change_list']) && $param['need_change_list'] == 'yes') {
            foreach ($filter as $filterKey => $value) {
                $filter['review_feedback.' . $filterKey] = $value;
                unset($filter[$filterKey]);
            }
        }
        if (!empty($filter['review_feedback.0'])) {
            $filter['0'] = $filter['review_feedback.0'];
            unset($filter['review_feedback.0']);
        }
        $order = $param["order"] ?? ["FIELD(status,'in_progress','not_started','final')", "review_feedback.created desc"];

        $getNeedChangeConfirmReviewFeedbackIds = '';
        // 新增
        if (!empty($param['need_change_type']) && $param['need_change_type'] == 'append') {
            $projectId = $param['filter']['project_id'] ?? 0;
            $stepCategoryId = $param['step_category_id'] ?? '';
            $departmentId = $param['department_id'] ?? 0;
            $moduleCode = $param['filter']['module_code'] ?? '';
            $startTime = $param['start_time'] ?? 0;
            $endTime = $param['end_time'] ?? 0;

            $reviewFeedbackIds = $this->appendReviewReedBackIds($projectId, $stepCategoryId, $departmentId, $moduleCode, $startTime, $endTime, 'review_feedback');
            if (empty($reviewFeedbackIds)) {
                return [];
            }
            $getNeedChangeConfirmReviewFeedbackIds = $reviewFeedbackIds;
            $reviewFeedbackModel->where(['review_feedback.id' => ['IN', $getNeedChangeConfirmReviewFeedbackIds]]);
        }
        // 返修
        if (!empty($param['need_change_type']) && $param['need_change_type'] == 'repair') {

            $projectId = $param['filter']['project_id'] ?? 0;
            $stepCategoryId = $param['step_category_id'] ?? '';
            $departmentId = $param['department_id'] ?? 0;
            $moduleCode = $param['filter']['module_code'] ?? '';
            $startTime = $param['start_time'] ?? 0;
            $endTime = $param['end_time'] ?? 0;
            $repairReviewFeedBackIds = $this->appendRepairReedBackIds($projectId, $stepCategoryId, $departmentId, $moduleCode, $startTime, $endTime, 'review_feedback');
            if (empty($repairReviewFeedBackIds)) {
                return [];
            }
            $getNeedChangeConfirmReviewFeedbackIds = $repairReviewFeedBackIds;
            $reviewFeedbackModel->where(['review_feedback.id' => ['IN', $getNeedChangeConfirmReviewFeedbackIds]]);
        }

        // 废除
        if (!empty($param['need_change_type']) && $param['need_change_type'] == 'abo') {

            $projectId = $param['filter']['project_id'] ?? 0;
            $stepCategoryId = $param['step_category_id'] ?? '';
            $departmentId = $param['department_id'] ?? 0;
            $moduleCode = $param['filter']['module_code'] ?? '';
            $startTime = $param['start_time'] ?? 0;
            $endTime = $param['end_time'] ?? 0;
            $aboRepairReedBackIds = $this->aboRepairReedBackIds($projectId, $stepCategoryId, $departmentId, $moduleCode, $startTime, $endTime, 'review_feedback');
            if (empty($aboRepairReedBackIds)) {
                return [];
            }
            $reviewFeedbackModel->where(['review_feedback.id' => ['IN', $aboRepairReedBackIds]]);
        }
        // 提出环节
        if (!empty($param['proposal_stage'])) {
            $showStepCategory = ProjectService::getInstance()->getShowStepCategoryGroup();
            $showStepCategoryMap = array_column($showStepCategory, null, 'id');
            $stepCategoryIds = [];
            foreach ($param['proposal_stage'] as $showStepCategoryName) {
                if (!empty($showStepCategoryMap[$showStepCategoryName])) {
                    foreach ($showStepCategoryMap[$showStepCategoryName]['children_ids'] as $stepCategoryId) {
                        $stepCategoryIds[] = $stepCategoryId;
                    }
                }
            }
            if (!empty($stepCategoryIds)) {
                $where = '(';
                foreach ($stepCategoryIds as $assetEntityId) {
                    $where .= "find_in_set({$assetEntityId},review_feedback.step_category_ids)";
                    $where .= ' OR ';
                }
                $where = trim($where, ' OR');
                $where .= ')';
                $reviewFeedbackModel->where($where);
            }
        }
        // 仅显示未确认
        if (!empty($param['only_not_confirm']) && $param['only_not_confirm'] == 'yes') {
            // 排除我已经确认过的
            $myConfirmReviewFeedbackModel = model(ReviewFeedbackModel::class)
                ->field('review_feedback.id as review_feedback_ids')
                ->join("review_feedback_confirm on review_feedback_confirm.review_feedback_id = review_feedback.id");

            if (!empty($param['filter']['project_id'])) {
                $myConfirmReviewFeedbackModel->where(['review_feedback.project_id' => $param['filter']['project_id']]);
            }
            if (!empty($param['filter']['module_code'])) {
                $myConfirmReviewFeedbackModel->where(['review_feedback.module_code' => $param['filter']['module_code']]);
            }
            $myConfirmReviewFeedbackIds = $myConfirmReviewFeedbackModel->where(['review_feedback_confirm.user_id' => ["EQ", request()->getUserId()]])->column('review_feedback_ids');
            if (!empty($myConfirmReviewFeedbackIds)) {
                $reviewFeedbackModel->where(['review_feedback.id' => ['NOT IN', $myConfirmReviewFeedbackIds]]);
            }
        }
        // 过滤集
        if (!empty($episodeCodes)) {
            $reviewFeedbackModel->where(["episode_codes" => $episodeCodes]);
        }
        // 过滤待我确认的
        if (!empty($param['wait_me_confirm']) && $param['wait_me_confirm'] == 'yes') {
            $myConfirmList = model(ProjectStepCategoryConfirmConfigModel::class)
                ->where([
                    'project_step_category_confirm_config.type' => ProjectStepCategoryConfirmConfigModel::TYPE_DEMAND_ORDER_CONFIRM,
                    'confirm_user_id' => \request()->getUserId(),
                ])
                ->field('project_id, step_category_id')
                ->select();
            $projectStepCategoryConfirm = [];
            // 需求单我能确认的项目环节打组
            foreach ($myConfirmList as $configItem) {
                $projectId = $configItem['project_id'];
                $stepCategoryId = $configItem['step_category_id'];
                if (!isset($projectStepCategoryConfirm[$projectId])) {
                    $projectStepCategoryConfirm[$projectId] = [];
                }
                $projectStepCategoryConfirm[$projectId][$stepCategoryId] = $stepCategoryId;
            }
            // 组装项目环节filter
            $projectStepCategoryConfirmFilter = [];
            foreach ($projectStepCategoryConfirm as $projectId => $stepCategoryIdList) {
                if (empty($stepCategoryIdList)) {
                    continue;
                }
                $projectStepCategoryConfirmFilter[] = [
                    'review_feedback.project_id' => $projectId,
                    'note_entity_relation.step_category_id' => ['in', $stepCategoryIdList]
                ];

            }
            if (count($projectStepCategoryConfirmFilter) > 1) {
                $projectStepCategoryConfirmFilter['_logic'] = 'OR';
            }
            // 没有环节能确认的
            if (empty($projectStepCategoryConfirmFilter)) {
                $filter = ['1 = 0'];
            } else {
                $filterJoined = [];
                foreach ($filter as $key => $cond) {
                    if (strpos('.', $key) === false) {
                        $key = 'review_feedback.' . $key;
                    }
                    $filterJoined[$key] = $cond;
                }
                $filter = empty($projectStepCategoryConfirmFilter)
                    ? $filterJoined
                    : [$filterJoined, $projectStepCategoryConfirmFilter];
                $reviewFeedbackModel = $reviewFeedbackModel
                    ->join('note_entity_relation on note_entity_relation.review_feedback_id = review_feedback.id', 'left')
                    ->group('review_feedback.id');
            }
        }

        $reviewFeedbackEntityType = $param['review_feedback_entity_type'] ?? '';
        if (!empty($reviewFeedbackEntityType) && !in_array($reviewFeedbackEntityType, ['append', 'modify'])) {
            return [];
        }
        // 需求实体:新增
        if (!empty($reviewFeedbackEntityType) && $reviewFeedbackEntityType == 'append') {
            $reviewFeedbackModel->join('review_feedback_entity rfe on rfe.review_feedback_id = review_feedback.id')
                ->where(['rfe.is_append' => 'yes'])
                ->group('review_feedback.id');
        }
        // 需求实体:返修
        if (!empty($reviewFeedbackEntityType) && $reviewFeedbackEntityType == 'modify') {
            $reviewFeedbackModel->join('review_feedback_entity rfe on rfe.review_feedback_id = review_feedback.id')
                ->where(['rfe.is_append' => 'no', 'rfe.enable' => 'default'])
                ->group(' review_feedback.id');
        }

        if (empty($fields)) {
            $fields = 'review_feedback.*';
        }
        $demandOrderList = $reviewFeedbackModel
            ->where($filter)
            ->field($fields)
            ->page(...$page)
            ->order($order)
            ->select();
        if (empty($demandOrderList)) {
            return [];
        }
//        if (!empty($fields) && $fields == 'review_feedback.id') {
//            return $demandOrderList;
//        }
        //创建人id
        $demandOrderUserId = [];
        $cosMediaListData = [];
        $projectIds = [];
        $stageIds = [];
        foreach ($demandOrderList as &$demandOrderItem) {
            $demandOrderUserId[] = $demandOrderItem['created_by'];
            $demandOrderUserId[] = $demandOrderItem['proposer'];
            $demandOrderItem["json"] = json_decode($demandOrderItem["json"], true);
            $projectIds[$demandOrderItem['project_id']] = $demandOrderItem['project_id'];

            if (!empty($demandOrderItem['stage_id'])) {
                $stageIds[$demandOrderItem['stage_id']] = $demandOrderItem['stage_id'];
            }

            if (!empty($demandOrderItem["json"]["review_feedback_cos_media"])) {
                $reviewFeedbackCosMedia = explode(",", $demandOrderItem["json"]["review_feedback_cos_media"]);
                foreach ($reviewFeedbackCosMedia as $reviewFeedbackCosMediaItem) {
                    $cosMediaListData[$reviewFeedbackCosMediaItem] = $reviewFeedbackCosMediaItem;
                }

                $demandOrderItem["review_feedback_cos_media"] = $reviewFeedbackCosMedia;
            }

            // 环节ID列表 返回int数组
            $demandOrderItem['step_category_ids'] = explode(',', $demandOrderItem['step_category_ids']);
            array_walk($demandOrderItem['step_category_ids'], fn(&$item) => ($item = intval($item)));
            unset($demandOrderItem["json"]);
        }

        $projectIds = array_values($projectIds);

        $demandOrderUserId = array_unique($demandOrderUserId);

        $cosMediaDataList = [];
        if (!empty($cosMediaListData)) {
            $cosMediaList = model(CosMediaModel::class)
                ->where(['id' => ["IN", join(",", $cosMediaListData)]])
                ->select();
            foreach ($cosMediaList as $cosMediaItem) {
                $cosMediaItem['param'] = json_decode($cosMediaItem['param'], true);
                $cosMediaDataList[$cosMediaItem["id"]] = $cosMediaItem;
            }
        }
        $projectMap = [];
        if (!empty($projectIds)) {
            $projectList = model(ProjectModel::class)
                ->where(['id' => ["IN", $projectIds]])
                ->field("id,name")
                ->select();
            $projectMap = array_column($projectList, null, 'id');
        }

        //查询创建人
        $demandOrderUserMap = [];
        if (!empty($demandOrderUserId)) {
            $demandOrderUserData = model(UserModel::class)
                ->where(["id" => ["IN", $demandOrderUserId]])
                ->field("id,name")
                ->select();
            $demandOrderUserMap = array_column($demandOrderUserData, null, "id");
        }

        $reviewFeedbackIds = array_column($demandOrderList, 'id');
        // 变更内容
        $needChangeListConfirmMap = $this->getNeedChangeConfirmList($param, $param['filter']['module_code'] ?? '', $getNeedChangeConfirmReviewFeedbackIds);

        // 查询需求确认人员配置
        $defaultNeedOrderConfirmMap = [];
        $needOrderConfirmUserMap = [];
        $userIds = [];
        if (!empty($param['filter']['project_id'])) {
            $defaultNeedOrderConfirmList = model(ProjectStepCategoryConfirmConfigModel::class)
                ->where(['project_step_category_confirm_config.project_id' => $param['filter']['project_id']])
                ->where(['project_step_category_confirm_config.type' => ProjectStepCategoryConfirmConfigModel::TYPE_DEMAND_ORDER_CONFIRM])
                ->select();
            if (!empty($defaultNeedOrderConfirmList)) {
                $defaultNeedOrderConfirmMap = array_group_by($defaultNeedOrderConfirmList, 'step_category_id');
                $userIds = join(',', array_column($defaultNeedOrderConfirmList, 'confirm_user_id'));
                $userList = model(UserModel::class)
                    ->where(['id' => ['IN', $userIds]])
                    ->field('id,name,avatar')
                    ->select();
                $needOrderConfirmUserMap = array_column($userList, null, 'id');
            }
        }

        //查询阶段
        $stageMap = [];
        if (!empty($stageIds)) {
            $stageList = model(StageModel::class)
                ->where(['id' => ["IN", array_values($stageIds)]])
                ->field("id,name")
                ->select();
            $stageMap = array_column($stageList, null, 'id');
        }

        // 查询需求确认人
        $rfcList = model(ReviewFeedbackConfirmModel::class)
            ->where(['review_feedback_id' => ['IN', $reviewFeedbackIds]])
            ->field('review_feedback_id,user_id')
            ->select();
        $rfcMap = array_column($rfcList, null, 'review_feedback_id');

        // 需求确认状态
        $confirmMap = [];
        if (!empty($userIds)) {
            $reviewFeedbackConfirmList = model(ReviewFeedbackConfirmModel::class)
                ->where(['user_id' => request()->getUserId(), 'review_feedback_id' => ['IN', $reviewFeedbackIds]])
                ->select();
            if (!empty($reviewFeedbackConfirmList)) {
                $confirmMap = array_column($reviewFeedbackConfirmList, null, 'review_feedback_id');
            }
        }

        return array_map(function ($demandOrderItem) use ($demandOrderUserMap, $cosMediaDataList, $projectMap, $needChangeListConfirmMap, $defaultNeedOrderConfirmMap, $needOrderConfirmUserMap, $rfcMap, $confirmMap, $stageMap) {
            $demandOrderItem["cos_media"] = [];
            if (!empty($demandOrderItem["review_feedback_cos_media"])) {
                foreach ($demandOrderItem["review_feedback_cos_media"] as $reviewFeedbackCosMedia) {
                    if (isset($cosMediaDataList[$reviewFeedbackCosMedia])) {
                        $demandOrderItem["cos_media"][] = $cosMediaDataList[$reviewFeedbackCosMedia];
                    }
                }
                unset($demandOrderItem["review_feedback_cos_media"]);
            }

            if (empty($demandOrderItem["cos_media"])) {
                unset($demandOrderItem["cos_media"]);
            }

            // 处理每个环节需求的确认人
            $tmpConfirmList = [];
            $tmpStepCategoryId = $demandOrderItem['step_category_ids'][0] ?? 0;
            if (!empty($defaultNeedOrderConfirmMap[$tmpStepCategoryId])) {
                foreach (array_column($defaultNeedOrderConfirmMap[$tmpStepCategoryId], 'confirm_user_id') as $userId) {
                    $tmpConfirm = 'no';
                    if (!empty($rfcMap[$demandOrderItem['id']]) && $rfcMap[$demandOrderItem['id']]['user_id'] == $userId) {
                        $tmpConfirm = 'yes';
                    }
                    $tmpConfirmList[] = [
                        'id' => $userId,
                        'name' => $needOrderConfirmUserMap[$userId]['name'],
                        'confirm' => $tmpConfirm,
                    ];
                }
            }

            $demandOrderItem['project_name'] = $projectMap[$demandOrderItem['project_id']]['name'];
            $demandOrderItem["created_by"] = $demandOrderUserMap[$demandOrderItem["created_by"]] ?? [];
            $demandOrderItem["proposer"] = $demandOrderUserMap[$demandOrderItem["proposer"]] ?? [];
            $demandOrderItem['append_list'] = $needChangeListConfirmMap['append'][$demandOrderItem['id']] ?? [];
            $demandOrderItem['repair_list'] = $needChangeListConfirmMap['repair'][$demandOrderItem['id']] ?? [];
            $demandOrderItem['confirm_list'] = $tmpConfirmList;
            $demandOrderItem['confirm'] = empty($confirmMap[$demandOrderItem['id']]) ? 'no' : 'yes';
            $demandOrderItem['stage'] = $stageMap[$demandOrderItem['stage_id']] ?? null;

            return $demandOrderItem;
        }, $demandOrderList);
    }

    /**
     * 过滤部门filter条件
     * @param $param
     * @param $appendReviewFeedbackModel
     * @return mixed
     */
    public function filterStepCategoryDepartment($param, $appendReviewFeedbackModel)
    {
        if (empty($param['step_category_id']) && empty($param['department_id'])) {
            $appendReviewFeedbackModel
                ->join('task_member on task_member.task_id = task.id')
                ->where(['task_member.partner' => request()->getUserId()]);
        }
        // 过滤环节
        if (!empty($param['step_category_id'])) {
            $appendReviewFeedbackModel
                ->join("task_relation_tag on task_relation_tag.task_id = task.id and link_module_code in ('show_step_category','step_category')")
                ->where(['task_relation_tag.link_id' => ['IN', $param['step_category_id']]]);
        }
        // 过滤部门
        if (!empty($param['department_id'])) {
            $du = TenantService::getInstance()->selectDepartmentUser(request()->getTenantId(), [
                'param' => [
                    'filter' => [
                        'department_id' => $param['department_id'],
                    ],
                ],
            ]);
            $saasUserIdList = array_column($du['rows'], 'saas_user_id');
            $appendReviewFeedbackModel
                ->join('task_member on task_member.task_id = task.id')
                ->where(['task_member.partner' => ['IN', $saasUserIdList]]);
        }
        return $appendReviewFeedbackModel;
    }

    /**
     * 新增需求ids
     * @param $projectId
     * @param $stepCategoryId
     * @param $departmentId
     * @param $moduleCode
     * @param $startTime
     * @param $endTime
     * @param $type
     * @return array
     */
    public function appendReviewReedBackIds($projectId, $stepCategoryId, $departmentId, $moduleCode, $startTime, $endTime, $type)
    {
        $filter['step_category_id'] = $stepCategoryId;
        $filter['department_id'] = $departmentId;
        $appendField = [
            "rfe.review_feedback_id as review_feedback_id",
            "task.id as task_id",
        ];

        $stepCategoryDefaultValueSql = $this->getDemandOrderStepCategoryDefaultValueSql($stepCategoryId);
        $appendReviewFeedbackModel = model(ReviewFeedbackModel::class);
        $appendReviewFeedbackModel->field($appendField)
            ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
            ->join('entity on entity.id = rfe.entity_id')
            ->join('task on entity.id = task.source_entity_id')
            ->where(['entity.project_id' => $projectId])
            ->where(['rfe.published' => 'yes'])
            ->where(['rfe.is_append' => 'yes'])
            ->where(['task.step_type' => 'step'])
            ->where("task.json ->> '$.task_status' <> 3")
            ->where(['rfe.published_time' => ['BETWEEN', [$startTime, $endTime]]]);
        if (!empty($moduleCode)) {
            $appendReviewFeedbackModel->where(['review_feedback.module_code' => $moduleCode]);
        }

        if (!empty($stepCategoryDefaultValueSql)) {
            $appendReviewFeedbackModel->where($stepCategoryDefaultValueSql);
        }

        $appendReviewFeedbackModel = $this->filterStepCategoryDepartment($filter, $appendReviewFeedbackModel);

        if ($type === 'review_feedback') {
            $appendReviewFeedbackIds = $appendReviewFeedbackModel
                ->group('review_feedback_id')
                ->column('review_feedback_id');
            if (empty($appendReviewFeedbackIds)) {
                return [];
            }
            return $appendReviewFeedbackIds;
        }
        if ($type == 'task') {
            $appendReviewTaskIds = $appendReviewFeedbackModel->group('task.id')->column('task_id');
            if (empty($appendReviewTaskIds)) {
                return [];
            }
            return $appendReviewTaskIds;
        }
        return [];
    }

    /**
     * 返修需求ids
     * @param $projectId
     * @param $stepCategoryId
     * @param $departmentId
     * @param $moduleCode
     * @param $startTime
     * @param $endTime
     * @param $type
     * @return array
     */
    public function appendRepairReedBackIds($projectId, $stepCategoryId, $departmentId, $moduleCode, $startTime, $endTime, $type)
    {
        $field = [
            'review_feedback.id as note_review_feedback_id',
            'task.id as task_id',
        ];
//        $repairReviewFeedBackModel = model(NoteModel::class)
//            ->field($field)
//            ->join('repair_order_affected_task roat ON roat.task_repair_order_id = note.task_repair_order_id')
//            ->join('task on task.id = roat.task_id')
//            ->join('entity on entity.id = task.entity_id')
//            ->join('review_feedback on review_feedback.id = note.review_feedback_id')
//            ->where(['note.demand_type' => 'review_feedback', 'note.project_id' => $projectId])
//            ->where(['roat.created' => ['BETWEEN', [$startTime, $endTime]]])
//            ->where(['task.step_type' => 'step']);

        // 已发布
        $repairReviewFeedBackModel = model(ReviewFeedbackModel::class)
            ->field($field)
            ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
            ->join("note_entity_relation on rfe.review_feedback_id = note_entity_relation.review_feedback_id and rfe.entity_id = note_entity_relation.entity_id and note_entity_relation.relation_type = 'step_category'")
            ->join('note on note.id = note_entity_relation.note_id')
            ->join('repair_order_affected_task roat on roat.task_repair_order_id = note.task_repair_order_id')
            ->join('task on task.id = roat.task_id')
            ->where([
                'review_feedback.project_id' => $projectId,
                'rfe.published' => 'yes',
                'rfe.published_time' => ['BETWEEN', [$startTime, $endTime]]
            ]);

        if (!empty($moduleCode)) {
            $repairReviewFeedBackModel->where(['review_feedback.module_code' => $moduleCode]);
        }
        $filter['step_category_id'] = $stepCategoryId;
        $filter['department_id'] = $departmentId;
        $repairReviewFeedBackModel = $this->filterStepCategoryDepartment($filter, $repairReviewFeedBackModel);
        if ($type === 'review_feedback') {
            $repairReviewFeedBackIds = $repairReviewFeedBackModel->column('note_review_feedback_id');
            if (empty($repairReviewFeedBackIds)) {
                return [];
            }
            return $repairReviewFeedBackIds;
        }
        if ($type == 'task') {
            $appendReviewTaskIds = $repairReviewFeedBackModel
                ->group('task.id')
                ->column('task_id');
            if (empty($appendReviewTaskIds)) {
                return [];
            }
            return $appendReviewTaskIds;
        }
        return [];
    }

    /**
     * 废除任务ids
     * @param $projectId
     * @param $stepCategoryId
     * @param $departmentId
     * @param $moduleCode
     * @param $startTime
     * @param $endTime
     * @param $type
     * @return array
     */
    public function aboRepairReedBackIds($projectId, $stepCategoryId, $departmentId, $moduleCode, $startTime, $endTime, $type)
    {
        $field = [
            'rfe.review_feedback_id',
            'task.id as task_id',
        ];

        $stepCategoryDefaultValueSql = $this->getDemandOrderStepCategoryDefaultValueSql($stepCategoryId);
        $reviewFeedbackModel = model(ReviewFeedbackModel::class)
            ->field($field)
            ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
            ->where(['rfe.enable' => 'no'])
            ->join('entity on entity.id = rfe.entity_id', 'LEFT')
            ->join('task on entity.id = task.source_entity_id', 'LEFT');
        if (!empty($projectId)) {
            $reviewFeedbackModel->where(['review_feedback.project_id' => $projectId]);
        }
        if (!empty($startTime) && !empty($endTime)) {
            $reviewFeedbackModel->where(['rfe.published_time' => ['BETWEEN', [$startTime, $endTime]]]);
        }
        if (!empty($moduleCode)) {
            $reviewFeedbackModel->where(['review_feedback.module_code' => $moduleCode]);
        }

        if (!empty($stepCategoryDefaultValueSql)) {
            $reviewFeedbackModel->where($stepCategoryDefaultValueSql);
        }

        $filter['step_category_id'] = $stepCategoryId;
        $filter['department_id'] = $departmentId;
        $reviewFeedbackModel = $this->filterStepCategoryDepartment($filter, $reviewFeedbackModel);
        if ($type == 'review_feedback') {
            $aboReviewFeedBackIds = $reviewFeedbackModel->column('review_feedback_id');
            if (empty($aboReviewFeedBackIds)) {
                return [];
            }
            return $aboReviewFeedBackIds;
        }
        if ($type == 'task') {
            $aboReviewFeedBackIds = $reviewFeedbackModel->column('task_id');
            if (empty($aboReviewFeedBackIds)) {
                return [];
            }
            return $aboReviewFeedBackIds;
        }
        return [];
    }

    /**
     * 需求变更内容
     * @param $param
     * @param $moduleCode
     * @param $getNeedChangeConfirmReviewFeedbackIds
     * @return array
     */
    public function getNeedChangeConfirmList($param, $moduleCode, $getNeedChangeConfirmReviewFeedbackIds)
    {
        if (empty($getNeedChangeConfirmReviewFeedbackIds)) {
            return [];
        }
        if (empty($param['need_change_list'])) {
            return [];
        }
        if ($param['need_change_list'] != 'yes') {
            return [];
        }
        if ($moduleCode == 'shot') {
            $options = OptionsService::getInstance()->getOptionsData("shot_demand_order_step_category_config");
        } else {
            $options = OptionsService::getInstance()->getOptionsData("asset_demand_order_step_category_config");
        }
        $stepCategoryMap = [];
        foreach ($options as $optionsItem) {
            if (!empty($optionsItem['step_category_id'])) {
                $stepCategoryMap[$optionsItem['step_category_id']] = $optionsItem;
            }
        }
        $closed = StatusService::getInstance()->getTaskDefaultClosedStatus();

        $stepCategoryDefaultValueSql = $this->getDemandOrderStepCategoryDefaultValueSql($param['step_category_id']);
        // 新增
        $append = [];
        if ($moduleCode == 'asset') {
            $appendField = [
                "rfe.review_feedback_id as review_feedback_id",
                "entity.json ->> '$.design_category' as category",
                "entity.json ->> '$.design_grade' as grade",
                "count(distinct task.id) as num",
            ];
            $appendReviewFeedbackModel = model(ReviewFeedbackModel::class)
                ->field($appendField)
                ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
                ->join('`entity` on entity.id = rfe.entity_id')
                ->join('task on entity.id = task.source_entity_id')
                ->where(['review_feedback.id' => ['IN', $getNeedChangeConfirmReviewFeedbackIds]])
                ->where(['task.step_type' => 'step'])
                ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $closed['id']]])
                ->where(['rfe.published' => 'yes'])
                ->where(['rfe.is_append' => 'yes']);

            if (!empty($param['start_time']) && !empty($param['end_time'])) {
                $appendReviewFeedbackModel->where(['rfe.published_time' => ['BETWEEN', [$param['start_time'], $param['end_time']]]]);
            }

            if (!empty($param['filter']['project_id'])) {
                $appendReviewFeedbackModel->where(['task.project_id' => $param['filter']['project_id']]);
            }

            $appendReviewFeedbackModel = $this->filterStepCategoryDepartment($param, $appendReviewFeedbackModel);
            if (!empty($stepCategoryDefaultValueSql)) {
                $appendReviewFeedbackModel->where($stepCategoryDefaultValueSql);
            }
            $appendList = $appendReviewFeedbackModel->group('review_feedback_id,category,grade')->select();
            if (!empty($appendList)) {
                $appendGroupList = array_group_by($appendList, 'review_feedback_id', 'category');
                foreach ($appendGroupList as $reviewFeedbackId => $category) {
                    foreach ($category as $categoryName => $grade) {
                        $categoryList = [
                            'name' => $categoryName,
                            'num' => array_sum(array_column($grade, 'num')),
                            'grade' => $grade,
                        ];
                        $append[$reviewFeedbackId][] = $categoryList;
                    }
                }
            }
        } else {
            $appendField = [
                "rfe.review_feedback_id as review_feedback_id",
                "task.step_category_id",
                "count(distinct task.id) as num",
            ];
            $appendReviewFeedbackModel = model(ReviewFeedbackModel::class)
                ->field($appendField)
                ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
                ->join('`entity` on entity.id = rfe.entity_id')
                ->join('task on entity.id = task.source_entity_id')
                ->where(['review_feedback.id' => ['IN', $getNeedChangeConfirmReviewFeedbackIds]])
                ->where(['task.step_type' => 'step'])
                ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $closed['id']]])
                ->where(['rfe.published' => 'yes'])
                ->where(['rfe.is_append' => 'yes']);

            if (!empty($param['start_time']) && !empty($param['end_time'])) {
                $appendReviewFeedbackModel->where(['rfe.published_time' => ['BETWEEN', [$param['start_time'], $param['end_time']]]]);
            }

            if (!empty($param['filter']['project_id'])) {
                $appendReviewFeedbackModel->where(['task.project_id' => $param['filter']['project_id']]);
            }

            $appendReviewFeedbackModel = $this->filterStepCategoryDepartment($param, $appendReviewFeedbackModel);

            if (!empty($stepCategoryDefaultValueSql)) {
                $appendReviewFeedbackModel->where($stepCategoryDefaultValueSql);
            }

            $appendList = $appendReviewFeedbackModel
                ->group('review_feedback_id,step_category_id')
                ->select();
            if (!empty($appendList)) {
                $appendGroupList = array_group_by($appendList, 'review_feedback_id');
                foreach ($appendGroupList as $reviewFeedbackId => $stepCategoryList) {
                    foreach ($stepCategoryList as $stepCategoryData) {
                        if (empty($stepCategoryMap[$stepCategoryData['step_category_id']])) {
                            continue;
                        }
                        $data = [
                            'name' => $stepCategoryMap[$stepCategoryData['step_category_id']]['name'],
                            'num' => $stepCategoryData['num'],
                            'step_category_id' => $stepCategoryData['step_category_id'],
                        ];
                        $append[$reviewFeedbackId][] = $data;
                    }
                }
            }
        }
        // 返修
        $repair = [];
        if ($moduleCode == 'asset') {
//            $repairReviewFeedbackModel = model(NoteModel::class)
//                ->field([
//                    'note.review_feedback_id',
//                    'roat.step_category_id',
//                    "JSON_UNQUOTE(JSON_EXTRACT(entity.json, '$.design_category')) as category",
//                    "JSON_UNQUOTE(JSON_EXTRACT(entity.json, '$.design_grade')) as grade",
//                    "count(distinct task.id) as num",
//                ])
//                ->join('repair_order_affected_task roat ON roat.task_repair_order_id = note.task_repair_order_id')
//                ->join('task on task.id = roat.task_id')
//                ->join('entity on entity.id = task.entity_id')
//                ->where(['note.review_feedback_id' => ['IN', $getNeedChangeConfirmReviewFeedbackIds]])
//                ->where(['task.step_type' => 'step'])
//                ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $closed['id']]]);
            $repairReviewFeedbackModel = model(ReviewFeedbackModel::class)
                ->field([
                    'note.review_feedback_id',
                    'roat.step_category_id',
                    "JSON_UNQUOTE(JSON_EXTRACT(entity.json, '$.design_category')) as category",
                    "JSON_UNQUOTE(JSON_EXTRACT(entity.json, '$.design_grade')) as grade",
                    "count(distinct task.id) as num",
                ])
                ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
                ->join("note_entity_relation on rfe.review_feedback_id = note_entity_relation.review_feedback_id and rfe.entity_id = note_entity_relation.entity_id and note_entity_relation.relation_type = 'step_category'")
                ->join('note on note.id = note_entity_relation.note_id')
                ->join('repair_order_affected_task roat on roat.task_repair_order_id = note.task_repair_order_id')
                ->join('task on task.id = roat.task_id')
                ->join('entity on entity.id = task.entity_id')
                ->where([
                    'review_feedback.id' => ["IN", $getNeedChangeConfirmReviewFeedbackIds],
                    'rfe.published' => 'yes',
                ]);

            if (!empty($param['start_time']) && !empty($param['end_time'])) {
                $repairReviewFeedbackModel->where([
                    'rfe.published_time' => ['BETWEEN', [$param['start_time'], $param['end_time']]]
                ]);
            }

            if (!empty($param['filter']['project_id'])) {
                $repairReviewFeedbackModel->where(['task.project_id' => $param['filter']['project_id']]);
            }

            $repairReviewFeedbackModel = $this->filterStepCategoryDepartment($param, $repairReviewFeedbackModel);
            $repairList = $repairReviewFeedbackModel
                ->group('review_feedback_id,category,grade')
                ->select();
            if (!empty($repairList)) {
                $repairMap = array_group_by($repairList, 'review_feedback_id', 'category');
                foreach ($repairMap as $reviewFeedbackId => $category) {
                    foreach ($category as $categoryName => $grade) {
                        $categoryList = [
                            'name' => $categoryName,
                            'num' => array_sum(array_column($grade, 'num')),
                            'grade' => $grade,
                        ];
                        $repair[$reviewFeedbackId][] = $categoryList;
                    }
                }
            }
        } else {
            $repairReviewFeedbackModel = model(ReviewFeedbackModel::class)
                ->field([
                    'note.review_feedback_id',
                    'roat.step_category_id',
                    "count(distinct task.id) as num",
                ])
                ->join('review_feedback_entity rfe on review_feedback.id = rfe.review_feedback_id')
                ->join("note_entity_relation on rfe.review_feedback_id = note_entity_relation.review_feedback_id and rfe.entity_id = note_entity_relation.entity_id and note_entity_relation.relation_type = 'step_category'")
                ->join('note on note.id = note_entity_relation.note_id')
                ->join('repair_order_affected_task roat on roat.task_repair_order_id = note.task_repair_order_id')
                ->join('task on task.id = roat.task_id')
                ->join('entity on entity.id = task.entity_id')
                ->where([
                    'review_feedback.id' => ["IN", $getNeedChangeConfirmReviewFeedbackIds],
                    'rfe.published' => 'yes',
                ]);

            if (!empty($param['start_time']) && !empty($param['end_time'])) {
                $repairReviewFeedbackModel->where([
                    'rfe.published_time' => ['BETWEEN', [$param['start_time'], $param['end_time']]]
                ]);
            }

            if (!empty($param['filter']['project_id'])) {
                $repairReviewFeedbackModel->where(['task.project_id' => $param['filter']['project_id']]);
            }

            $repairReviewFeedbackModel = $this->filterStepCategoryDepartment($param, $repairReviewFeedbackModel);
            $repairList = $repairReviewFeedbackModel->group('review_feedback_id,step_category_id')->select();
            if (!empty($repairList)) {
                $repairGroupMapList = array_group_by($repairList, 'review_feedback_id');
                foreach ($repairGroupMapList as $reviewFeedbackId => $stepCategoryList) {
                    foreach ($stepCategoryList as $stepCategoryData) {
                        if (empty($stepCategoryMap[$stepCategoryData['step_category_id']])) {
                            continue;
                        }
                        $data = [
                            'name' => $stepCategoryMap[$stepCategoryData['step_category_id']]['name'],
                            'num' => $stepCategoryData['num'],
                            'step_category_id' => $stepCategoryData['step_category_id'],
                        ];
                        $repair[$reviewFeedbackId][] = $data;
                    }
                }
            }
        }
        return [
            'append' => $append,
            'repair' => $repair,
        ];
    }

    /**
     * 导入需求
     * @param array $list
     * @param string $moduleCode
     * @param int $reviewFeedbackId
     * @param        $res
     * @param bool $skipNotChanged
     * @return array
     * @throws Exception
     * @throws \Exception
     */
    public function import(array $list, string $moduleCode, int $reviewFeedbackId, $res, bool $skipNotChanged)
    {
        $showSecondLevelStepCategoryList = StepCategoryService::getInstance()->showSecondLevelList();
        $assetStepCategoryIdList = [];
        $levelStepCategoryIdList = [];
        foreach ($showSecondLevelStepCategoryList as $showSecondLevelStepCategory) {
            switch ($showSecondLevelStepCategory['real_module_code']) {
                case 'level':
                    $levelStepCategoryIdList[] = $showSecondLevelStepCategory['id'];
                    break;
                case 'asset':
                    $assetStepCategoryIdList[] = $showSecondLevelStepCategory['id'];
                    break;
            }
        }
        // 找出本次导入的环节
        $showSecondLevelStepCategoryList = array_filter($showSecondLevelStepCategoryList, function ($i) use ($moduleCode) {
            return $i['module_code'] === $moduleCode;
        });

        if (empty($showSecondLevelStepCategoryList)) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::STEP_CATEGORY_NOT_FOUND;
                $i['err_msg'] = "导入的环节code找不到";
                return $i;
            }, $res);
        }

        $reviewFeedback = model(ReviewFeedbackModel::class)->find($reviewFeedbackId);
        if (empty($reviewFeedback)) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::REVIEW_FEEDBACK_NOT_FOUND;
                $i['err_msg'] = "需求单不存在";
                return $i;
            }, $res);
        }

        try {
            ReviewFeedbackService::getInstance()->reviewFeedbackPermissionsDeal($reviewFeedback["permissions"], "entry_review_feedback_note");
        } catch (ReviewFeedbackPermissionException $e) {
            return array_map(function ($i) use ($e) {
                $i['err_code'] = $e->getCode();
                $i['err_msg'] = "需求单权限验证不通过";
                return $i;
            }, $res);
        }

        if ($reviewFeedback['module_code'] !== $moduleCode) {
//            return array_map(function ($i) {
//                $i['err_code'] = ErrorCode::MODULE_CODE_NOT_IN_REVIEW_FEEDBACK;
//                $i['err_msg'] = "导入的数据不在需求单里";
//                return $i;
//            }, $res);
        }

        if ($reviewFeedback['status'] === ReviewFeedbackModel::STATUS_FINAL) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::REVIEW_FEEDBACK_CLOSED;
                $i['err_msg'] = "需求单已关闭";
                return $i;
            }, $res);
        }

        $reviewFeedbackInitialEpisodeCodeList = explode(",", $reviewFeedback['episode_codes']);
        $entityWhere = [];
        $baseWhere = ['project_id' => $reviewFeedback['project_id']];
        $fields = '*';
        $uniqueFunc = function ($i) {
            return strtoupper($i['name']);
        };
        $actuallyModuleCode = '';
        if ($moduleCode == 'asset') {
            $entityNameList = array_unique(array_column($list, 'name'));
            $entityWhere = ['name' => ['IN', implode(',', $entityNameList)]];
            $baseWhere['module_id'] = module_by_code('design')['id'];
            $fields .= ",concat(upper(name)) as unique_key";
            $actuallyModuleCode = 'design';
        } else {
            $uniqueFunc = function ($i) {
                return strtoupper($i['initial_episode_code']) . '#' . strtoupper($i['showings_number']) . '#' . strtoupper($i['name']);
            };
            $baseWhere['module_id'] = module_by_code('storyboard')['id'];
            $listGrouped = array_group_by($list, 'initial_episode_code', 'showings_number');
            $fields .= ",concat(upper(initial_episode_code),'#',upper(showings_number),'#',upper(name)) as unique_key";
            foreach ($listGrouped as $initialEpisodeCode => $listGroupedByShowingsNumber) {
                foreach ($listGroupedByShowingsNumber as $showingsNumber => $entityDataList) {
                    $entityNameList = array_unique(array_column($entityDataList, 'name'));
                    $entityWhere[] = [
                        'entity.initial_episode_code' => $initialEpisodeCode,
                        'entity.showings_number' => $showingsNumber,
                        'entity.name' => ['IN', implode(',', $entityNameList)],
                    ];
                }
            }
            if (count($entityWhere) === 1) {
                $entityWhere = $entityWhere[0];
            } else {
                $entityWhere['_logic'] = 'OR';
                $entityWhere = [$entityWhere];
            }
            $actuallyModuleCode = 'storyboard';
        }

        if (empty($entityWhere)) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::NO_DATA_HAS_BEEN_CHANGED;
                $i['err_msg'] = "没有需要导入的数据";
                return $i;
            }, $res);
        }

        $entityList = model(EntityModel::class)->where($baseWhere)
            ->where($entityWhere)
            ->field($fields)
            ->select();
        $entityList = array_column($entityList, null, 'unique_key');

        $reviewFeedbackEntityList = [];
        $otherReviewFeedbackEntityNotPublishedList = [];
        if (!empty($entityList)) {
            $reviewFeedbackEntityFilter = [
//                'review_feedback_id' => $reviewFeedbackId,
                'entity_id' => ['IN', implode(',', array_column($entityList, 'id'))],
            ];

            $reviewFeedbackEntityList = model(ReviewFeedbackEntityModel::class)
                ->where($reviewFeedbackEntityFilter)
                ->select();

            foreach ($reviewFeedbackEntityList as $reviewFeedbackEntity) {
                if ($reviewFeedbackEntity['review_feedback_id'] == $reviewFeedbackId) {
                    $reviewFeedbackEntityList[$reviewFeedbackEntity['entity_id']] = $reviewFeedbackEntity;
                } else {
                    if ($reviewFeedbackEntity['published'] === ReviewFeedbackEntityModel::PUBLISHED_NO) {
                        $otherReviewFeedbackEntityNotPublishedList[$reviewFeedbackEntity['entity_id']] = $reviewFeedbackEntity['entity_id'];
                    }
                }
            }
        }

        $draftStatus = StatusService::getInstance()->getDefaultDraftStatus();
        $entityService = EntityService::getInstance();
        $noteService = NoteService::getInstance();
        $moduleData = module_by_code($actuallyModuleCode);
        $entityModel = model(EntityModel::class);
        $entityModel->setCurrentModuleCode($actuallyModuleCode);
        $entityCommonService = CommonService::instance('entity');

        // 查询项目 字段验证配置
        $project = model(ProjectModel::class)->find($reviewFeedback['project_id']);
        $templateService = TemplateService::getInstance();
        $moduleFieldConfig = $templateService->getProjectTemplateModuleFieldConfig($project['project_template_id']);
        $moduleFieldCheck = $moduleFieldConfig[$actuallyModuleCode]['fields'] ?? [];
        $showSecondLevelStepCategoryList[] = [
            'code' => 'entity_demand',
            'name' => '实体需求',
            'type' => 'entity',
        ];
        $mfR = $this->getModuleCanSaveFields($actuallyModuleCode);
        $mfR = array_flip($mfR);
        $noteKeys = array_column($showSecondLevelStepCategoryList, 'code');
        $importCount = 0;

        $proposerMap = $this->getDemandProposer($list, $showSecondLevelStepCategoryList);

        foreach ($list as $listIndex => $item) {
            if ($res[$listIndex]['err_code'] !== 0) {
                continue;
            }
            if (!in_array($item['initial_episode_code'], $reviewFeedbackInitialEpisodeCodeList)) {
                $res[$listIndex]['err_code'] = ErrorCode::IMPORT_REVIEW_FEEDBACK_EPISODE_CODE_NOT_EXIST;
                $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']}集数不存在需求单中";
                continue;
            }
            try {
                $entityDataHandled = $entityCommonService->dealCreateCustomField($item, $actuallyModuleCode);
            } catch (HttpResponseException $e) {
                $eData = $e->getResponse()->getData();
                $res[$listIndex]['err_code'] = $eData['code'];
                $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} " . $eData['msg'];
                APP_DEBUG && trace(var_export($eData, true));
                continue;
            }
            if (isset($entityDataHandled['json'])) {
                foreach ($entityDataHandled['json'] as $jk => $jv) {
                    $entityDataHandled[$jk] = $jv;
                }
                unset($entityDataHandled['json']);
            }
            // 把插入需求单的实体信息 提前转换到处理完的entityData里
            foreach ($mfR as $entityCustomField => $reviewFeedbackField) {
                if (!empty($item[$reviewFeedbackField])) {
                    $entityDataHandled[$entityCustomField] = $item[$reviewFeedbackField];
                }
            }

            foreach ($entityDataHandled as $key => $value) {
                if (empty($moduleFieldCheck[$key]['validation_rules'])) {
                    continue;
                }
                if (!empty($moduleFieldCheck[$key]['default_prefix'])) {
                    $value = str_replace($moduleFieldCheck[$key]['default_prefix'], "", $value);
                }
                $validateRules = validate_input_type($moduleFieldCheck[$key]['validation_rules'], $value);
                if ($validateRules['code'] == 0) {
                    $validationRulesString = implode(',', $validateRules['preg']);
                    $res[$listIndex]['err_code'] = ErrorCode::PROJECT_TEMPLATE_VALIDATE_RULE_ERROR;
                    $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} $key: {$value} 不满足系统要求 (Fields [{$key}] only allow $validationRulesString)";
                    continue 2;
                }
            }

            $uk = $uniqueFunc($item);
            $entity = null;
            if (isset($entityList[$uk])) {
                $entityJson = json_decode($entityList[$uk]['json'], true);
                $entity = $entityList[$uk];
                foreach ($entityJson as $jk => $jv) {
                    $entity[$jk] = $jv;
                }
                unset($entity['json']);
                if (in_array($entity['id'], $otherReviewFeedbackEntityNotPublishedList)) {
                    $res[$listIndex]['err_code'] = ErrorCode::ALREADY_EXIST_IN_OTHER_DEMAND_ORDER;
                    $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} 已经存在于其他需求单";
                    continue;
                }
                if (isset($reviewFeedbackEntityList[$entityList[$uk]['id']]) &&
                    $reviewFeedbackEntityList[$entityList[$uk]['id']]['published'] === ReviewFeedbackEntityModel::PUBLISHED_YES
                ) {
                    $res[$listIndex]['err_code'] = ErrorCode::REVIEW_FEEDBACK_ENTITY_ALREADY_PUBLISHED;
                    $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} 已经发布过了";
                    continue;
                }
                // 检查实体是否存在修改 || 是否存在续期 || 是否存在启用和废除
                if ($skipNotChanged
                    && !$this->entityChanged($entityDataHandled, $entity)
                    && $this->emptyNote($item, $noteKeys)
                    && $this->reviewEntityEnableNotChanged($item, $entity)
                ) {
                    $res[$listIndex]['err_code'] = ErrorCode::NO_DATA_CHANGED;
                    $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} 没有任何数据变化";
                    continue;
                }

                // 存在的资产 判断类型是否一致
                if (isset($entityDataHandled['design_category']) && $entityDataHandled['design_category'] != $entity['design_category']) {
                    $res[$listIndex]['err_code'] = ErrorCode::ASSET_CATEGORY_NOT_SAME;
                    $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']}类型应该为[{$entity['design_category']}]";
                    continue;
                }
            } else {
                // 资产新增验证类型必传
                if ($actuallyModuleCode === 'design') {
                    if (empty($entityDataHandled['design_category'])) {
                        $res[$listIndex]['err_code'] = ErrorCode::ASSET_CATEGORY_CANT_BE_EMPTY;
                        $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']}类型不能为空";
                        continue;
                    }
                }
            }
            $entityModel->startTrans();
            try {
                if (!isset($entityList[$uk])) {
                    $entityDataHandled['project_id'] = $reviewFeedback['project_id'];
                    $entityDataHandled[$actuallyModuleCode . '_status'] = $draftStatus['id'];
                    request()->getModuleCode($actuallyModuleCode);
                    $f = $entityService->sampleCreate(['data' => $entityDataHandled, 'module_code' => $actuallyModuleCode], $moduleData, auto_fill_tenant_id());
                    $entityList[$uk] = model(EntityModel::class)->find($f['id']);
                    $entityJson = $f;
                    $entity = $entityList[$uk];
                }
                $entityIsLevel = isset($entityJson['design_category']) && $entityJson['design_category'] === '关卡';
                $reviewFeedbackEntityAddItem = [
                    'review_feedback_id' => $reviewFeedbackId,
                    'entity_id' => $entity['id'],
                    'name' => $item['name'],
                    'initial_episode_code' => $item['initial_episode_code'],
                    'showings_number' => $item['showings_number'],
                    'entity_module_id' => $entity['module_id'],
                    'is_append' => !isset($item['is_append']) || $item['is_append'] === 'default' ? $entity['is_append'] : $item['is_append'],
                    'enable' => $item['enable'] ?? ReviewFeedbackEntityModel::ENABLE_DEFAULT,
                    'review_feedback_entity_draft_data' => $entityDataHandled,
                    'stage_id' => $reviewFeedback['stage_id'],
                ];
                foreach ($item as $ik => $iv) {
                    if (in_array($ik, $this->allowPublishSaveFields)) {
                        $reviewFeedbackEntityAddItem[$ik] = $iv;
                    }
                }
                // 处理json字段的映射关系
                foreach ($mfR as $entityCustomField => $reviewFeedbackField) {
                    if (!empty($entityJson[$entityCustomField]) && empty($reviewFeedbackEntityAddItem[$reviewFeedbackField])) {
                        $reviewFeedbackEntityAddItem[$reviewFeedbackField] = $entityJson[$entityCustomField];
                    }
                }
                // 创建需求单实体
                request()->getModuleCode('review_feedback_entity');
                $defaultAttrMap = ModuleService::getInstance()->getModuleDefaultAttr('review_feedback_entity');
                $reviewFeedbackEntityAddItem = EntityService::getInstance()->mergeJsonFieldWithDefaultAttr($reviewFeedbackEntityAddItem, $defaultAttrMap);
                if (!isset($reviewFeedbackEntityList[$entityList[$uk]['id']])) {
                    $reviewFeedbackEntityList[$entity['id']] = CommonService::instance('review_feedback_entity')->create($reviewFeedbackEntityAddItem, 'review_feedback_entity', false);
                } else {
                    $reviewFeedbackEntityAddItem['id'] = $reviewFeedbackEntityList[$entityList[$uk]['id']]['id'];
                    $originalSpecialEffect = $reviewFeedbackEntityList[$entityList[$uk]['id']]['review_feedback_entity_fx'] ?? '';
                    $reviewFeedbackEntityJson = $reviewFeedbackEntityList[$entityList[$uk]['id']]['json'] ?? '';
                    $reviewFeedbackEntityJsonArr = model(ReviewFeedbackEntityModel::class)->getJsonAttr($reviewFeedbackEntityJson, []);
                    $originalSpecialEffectFromJson = $reviewFeedbackEntityJsonArr['review_feedback_entity_fx'] ?? ''; // json中原来的特效方式
                    $originalSpecialEffect = empty($originalSpecialEffect) ? $originalSpecialEffectFromJson : $originalSpecialEffect;

                    if (!empty($originalSpecialEffect)
                        && isset($item['review_feedback_entity_fx'])
                        && isset($item['complex_special_effect'])
                        && $item['complex_special_effect'] == 'yes'
                    ) {
                        $reviewFeedbackEntityAddItem['review_feedback_entity_fx'] = $this->handleComplexShotSpecialEffect(
                            $originalSpecialEffect,
                            $item['review_feedback_entity_fx']
                        );
                    }
                    $reviewFeedbackEntityList[$entity['id']] = CommonService::instance('review_feedback_entity')->update($reviewFeedbackEntityAddItem, 'review_feedback_entity', false);
                }

                // 处理环节需求
                foreach ($showSecondLevelStepCategoryList as $showSecondLevelStepCategoryItem) {
                    if (!isset($item[$showSecondLevelStepCategoryItem['code']])) {
                        continue;
                    }
                    if (empty($showSecondLevelStepCategoryItem['type']) || $showSecondLevelStepCategoryItem['type'] !== 'entity') {
                        if ($entityIsLevel && in_array($showSecondLevelStepCategoryItem['id'], $assetStepCategoryIdList)) {
                            // 关卡不允许导入资产需求
                            continue;
                        }
                        if (!$entityIsLevel && in_array($showSecondLevelStepCategoryItem['id'], $levelStepCategoryIdList)) {
                            // 非关卡不允许导入关卡需求
                            continue;
                        }
                    }

                    $stepCategoryNoteList = $item[$showSecondLevelStepCategoryItem['code']];
                    foreach ($stepCategoryNoteList as $stepCategoryNote) {
                        $proposer = [];
                        if (isset($stepCategoryNote['proposer']) && isset($stepCategoryNote['proposer_department'])) {
                            $proposer = $proposerMap[$stepCategoryNote['proposer'] . "_" . $stepCategoryNote['proposer_department']] ?? [];
                        }
                        $stepCategoryNote['proposer'] = $proposer['user']['saas_id'] ?? 0;
                        $stepCategoryNote['proposer_department'] = $proposer['department']['id'] ?? 0;
                        $tmp = [];
                        $stepCategoryNote['project_id'] = $reviewFeedback['project_id'];
                        $stepCategoryNote['module_code'] = $moduleCode;
                        $stepCategoryNote['review_feedback_id'] = $reviewFeedback['id'];
                        $stepCategoryNote['mark_modify'] = 'yes';
                        $stepCategoryNote['demand_type'] = NoteModel::DEMAND_TYPE_REVIEW_FEEDBACK;

                        $tmp['note'] = $stepCategoryNote;

                        if (!empty($showSecondLevelStepCategoryItem['type']) && $showSecondLevelStepCategoryItem['type'] === 'entity') {
                            $tmp['note_entity_relation'] = [[
                                'relation_type' => 'entity',
                                'project_id' => $project['id'],
                                'relate_module_code' => $moduleCode,
                                'entity_id' => $entity['id'],
                                'episode_code' => $item['initial_episode_code'],
                                'from_upstream_step_category_id' => 0,
                            ]];
                        } else {
                            if (!$entityIsLevel && in_array($showSecondLevelStepCategoryItem['id'], $levelStepCategoryIdList)) {
                                continue;
                            }
                            $tmp['note_entity_relation'] = [[
                                'relation_type' => 'step_category',
                                'entity_id' => $entity['id'],
                                'episode_code' => $item['initial_episode_code'],
                                'step_category_id' => $showSecondLevelStepCategoryItem['id'],
                                'project_id' => $project['id'],
                                'relate_module_code' => $moduleCode,
                                'from_upstream_step_category_id' => 0,
                            ]];
                            if (!empty($stepCategoryNote['repair_step_id'])) {
                                $tmp['note']['repair_step_id'] = $stepCategoryNote['repair_step_id'];
                            }
                            // 存在受影响的下游环节 绑定下游环节到当前需求上
                            if (!empty($stepCategoryNote['downstream_step_category_list'])) {
                                foreach ($stepCategoryNote['downstream_step_category_list'] as $downstreamStepCategoryId) {
                                    if (!$entityIsLevel && in_array($downstreamStepCategoryId, $levelStepCategoryIdList)) {
                                        continue;
                                    }
                                    $tempDownStreamStepCategoryNoteRelation = $tmp['note_entity_relation'][0];
                                    $tempDownStreamStepCategoryNoteRelation['step_category_id'] = $downstreamStepCategoryId;
                                    $tempDownStreamStepCategoryNoteRelation['from_upstream_step_category_id'] = $showSecondLevelStepCategoryItem['id'];
                                    $tmp['note_entity_relation'][] = $tempDownStreamStepCategoryNoteRelation;
                                }
                            }
                        }

                        request()->getModuleCode('note');
                        $noteService->createNote($tmp, false, true);
                    }
                }

                $entityModel->commit();
                $res[$listIndex]['entity_id'] = $entity['id'];
                $importCount += 1;
            } catch (HttpResponseException $e) {
                $entityModel->rollback();
                $eData = $e->getResponse()->getData();
                $res[$listIndex]['err_code'] = $eData['code'];
                $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} " . $this->getReturnMessage($eData['code'], $eData['msg']);
                APP_DEBUG && trace(var_export($eData, true));
                continue;
            } catch (Throwable $e) {
                $entityModel->rollback();
                $res[$listIndex]['err_code'] = $e->getCode();
                $res[$listIndex]['err_msg'] = "{$item['initial_episode_code']}/{$item['showings_number']}/{$item['name']} " . $e->getMessage();
                APP_DEBUG && trace(format_exception_info($e));
                continue;
            }
        }
        if ($importCount >= 1 && $reviewFeedback['status'] == ReviewFeedbackModel::STATUS_NOT_STARTED) {
            model(ReviewFeedbackModel::class)->modifyItem(['id' => $reviewFeedbackId, 'status' => ReviewFeedbackModel::STATUS_IN_PROGRESS]);
        }
        return $res;

    }

    /**
     * 表格导入---错误提示--返回中文提示
     * @param int $errCode 错误码
     * @param string $errStr 要转换的提示语
     * @return string
     */
    private function getReturnMessage(int $errCode, string $errStr)
    {
        $str = '';
        //字段--映射--中文
        $fieldMapStr = [
            'design_hair_making' => '毛发制作',
            'design_production_method' => '制作方式',
        ];
        //匹配相应中文
        foreach ($fieldMapStr as $k => $val) {
            if (strrpos($errStr, $k) !== false) {
                $str .= $val;
            }
        }
        if (empty($str)) {
            return $errStr;
        }

        switch ($errCode) {
            //值错误
            case ErrorCode::ATTRIBUTE_VALUE_NOT_ALLOWED:
                $str .= ' 数据不正确';
                break;
            default:
                break;
        }
        return $str;
    }

    /**
     * 发布需求
     * @param int $userId
     * @param int $reviewFeedbackId
     * @param string $moduleCode
     * @param array $paramEntityIdList
     * @return array
     * @throws \Exception
     */
    public function publish(int $userId, int $reviewFeedbackId, string $moduleCode, array $paramEntityIdList)
    {
        $res = array_map(function ($i) {
            return [
                'entity_id' => $i,
                'err_code' => 0,
                'err_msg' => 'OK',
            ];
        }, $paramEntityIdList);
        $hookData = [
            'demand_order_id' => $reviewFeedbackId
        ];
        $reviewFeedback = model(ReviewFeedbackModel::class)->find($reviewFeedbackId);
        if (empty($reviewFeedback)) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::REVIEW_FEEDBACK_NOT_FOUND;
                $i['err_msg'] = "需求单不存在";
                return $i;
            }, $res);
        }

        if ($reviewFeedback['status'] === ReviewFeedbackModel::STATUS_FINAL) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::REVIEW_FEEDBACK_CLOSED;
                $i['err_msg'] = "需求单已经关闭";
                return $i;
            }, $res);
        }

        //关闭需求单 确认所有的需求单状态处于关闭的状态下
        Client::send('check_demand_order_closed', build_queue_data_with_xu(['review_feedback_id' => $reviewFeedbackId]), 10);

        // 自动接受所有未确认需求
        $this->acceptAll($reviewFeedbackId, $userId);

        // 反馈实体信息查询
        $reviewFeedbackEntityList = model(ReviewFeedbackEntityModel::class)
            ->where(['review_feedback_id' => $reviewFeedbackId, 'entity_id' => ['IN', implode(',', $paramEntityIdList)]])
            ->where(['published' => ReviewFeedbackEntityModel::PUBLISHED_NO])
            ->select();
        if (empty($reviewFeedbackEntityList)) {
            return array_map(function ($i) {
                $i['err_code'] = ErrorCode::NO_DATA_HAS_BEEN_CHANGED;
                $i['err_msg'] = "没有需要发布的实体";
                return $i;
            }, $res);
        }
        $reviewFeedbackEntityList = array_column($reviewFeedbackEntityList, null, 'entity_id');
        $entityIdList = array_keys($reviewFeedbackEntityList);
        $entityList = model(EntityModel::class)
            ->where(['id' => ['IN', implode(',', $entityIdList)]])
            ->select();

        // 下游实体(资产/关卡/镜头)查询
        $entityDownstreamEntityMap = EntityService::getInstance()->getDownstreamEntityIdMap($entityList, $moduleCode);

        $noteFields = "note.*,note.json->>'$.reason_type' as reason_type";
        // 查询出待发布的需求 非上游影响需求
        $noteList = model(NoteModel::class)
            ->join('note_entity_relation on note.id = note_entity_relation.note_id')
            ->where([
                'note_entity_relation.review_feedback_id' => $reviewFeedbackId,
                'note_entity_relation.relation_type' => NoteEntityRelationModel::RELATION_TYPE_STEP_CATEGORY,
                'note_entity_relation.entity_id' => ['IN', implode(',', $entityIdList)],
                'note_entity_relation.from_upstream_step_category_id' => 0
            ])
            ->where(['note.demand_status' => NoteModel::DEMAND_STATUS_PENDING])
            ->field($noteFields)
            ->select();

        //获取需求实体计划数据
        list($stepCategoryTaskDefaultValueMap, $stepCategoryIds, $planMap, $realEntityList, $childrenStepCategoryMap, $episodeCodeIdMap) = $this->getDemandEntityPlanData($paramEntityIdList, $reviewFeedback);

        $noteMap = array_column($noteList, null, 'id');
        $noteGrouped = [];
        $entityStepCategoryRelationList = [];
        $downstreamDontRepairStepCategoryIdListGrouped = []; // 下游不返修环节列表分组
        $childrenStepCategoryParentMap = [];
        $noteEntityStepCategoryIds = [];
        if (!empty($noteList)) {
            $noteIdList = array_column($noteList, 'id');
            $noteRelationList = model(NoteEntityRelationModel::class)
                ->where(['note_id' => ['IN', $noteIdList]])
                ->select();
            foreach ($noteRelationList as $noteRelation) {
                if ($noteRelation['from_upstream_step_category_id'] > 0) {
                    // 上游影响的需求 记录不返修的状态
                    if ($noteRelation['repair_accept_status'] === 'no') {
                        $downstreamDontRepairStepCategoryIdListGrouped[$noteRelation['note_id']][] = $noteRelation['step_category_id'];
                    } else {
                        $noteEntityStepCategoryIds[$noteRelation['entity_id']][$noteRelation['step_category_id']] = $noteRelation['step_category_id'];
                    }
                } else {
                    // 导入的原始需求
                    $note = $noteMap[$noteRelation['note_id']];
                    $noteGrouped[$noteRelation['entity_id']][$noteRelation['step_category_id']][$note['reason_type']][] = $note;

                    // $childrenStepCategoryMap 是从 options 里查出来的需求单配置，其中某列包含多个小环节，取其中一个环节id作为索引（如 绑定4 引擎设置 5，实际绑定列的id 为 4）
                    // note_entity_relation也只插入此环节id（实际插入 4）
                    // 创建延期时只会查询实体 $noteEntityStepCategoryIds 中环节的任务
                    // 因此，此处应该将所有子环节均插入 $noteEntityStepCategoryIds（4 和 5）
                    // 保证有需求的环节任务均被延期
                    if (isset($childrenStepCategoryMap[$noteRelation['step_category_id']])) {
                        foreach ($childrenStepCategoryMap[$noteRelation['step_category_id']] as $childrenStepCategoryId) {
                            $entityStepCategoryRelationList[$noteRelation['entity_id']][$childrenStepCategoryId] = $childrenStepCategoryId;
                            $noteEntityStepCategoryIds[$noteRelation['entity_id']][$childrenStepCategoryId] = $childrenStepCategoryId;
                            $childrenStepCategoryParentMap[$childrenStepCategoryId] = $noteRelation['step_category_id'];
                        }
                    } else {
                        $entityStepCategoryRelationList[$noteRelation['entity_id']][$noteRelation['step_category_id']] = $noteRelation['step_category_id'];
                        $noteEntityStepCategoryIds[$noteRelation['entity_id']][$noteRelation['step_category_id']] = $noteRelation['step_category_id'];
                        $childrenStepCategoryParentMap[$noteRelation['step_category_id']] = $noteRelation['step_category_id'];
                    }
                }

            }
        }

        $entityTaskList = [];

        $entityList = array_column($entityList, null, 'id');

        // 查询实体任务
        if (!empty($entityStepCategoryRelationList)) {
            $entityTaskFilter = [];
            foreach ($entityStepCategoryRelationList as $entityId => $entityStepCategoryRelationListItem) {
                $currentEntityIdScope = [$entityId];
                if (isset($entityDownstreamEntityMap[$entityId])) {
                    $currentEntityIdScope[] = $entityDownstreamEntityMap[$entityId];
                }
                $entityTaskFilter[] = [
                    'entity_id' => ['IN', $currentEntityIdScope],
                    'step_category_id' => ['IN', implode(',', array_keys($entityStepCategoryRelationListItem))],
                ];
            }
            if (count($entityTaskFilter) === 1) {
                $entityTaskFilter = $entityTaskFilter[0];
            } else {
                $entityTaskFilter['_logic'] = 'OR';
                $entityTaskFilter = [$entityTaskFilter];
            }

            $entityTaskList = model(TaskModel::class)
                ->where($entityTaskFilter)
                ->where(['step_type' => TaskModel::STEP_TYPE_STEP])
                ->field("*,task.json->>'$.task_status' task_status")
                ->select();
            // 处理格式 ["entity_id#step_category_id" => $entityTask]
            $entityTaskList = $this->dealDemandOrderEntityTaskList($entityTaskList, $childrenStepCategoryParentMap);
        }

        $reviewing = StatusService::getInstance()->getTaskDefaultReviewingStatus();
        $partyAReviewing = StatusService::getInstance()->getTaskWaitForPartyAReviewStatus();
        $publishStatus = StatusService::getInstance()->getTaskReadyToPublishStatus();
        $doneStatus = StatusService::getInstance()->getTaskDoneStatus();
        $waitPartyBSubmitStatus = StatusService::getInstance()->getTaskWaitForPartyBSubmitReviewStatus();

        $reviewedStatus = StatusService::getInstance()->getTaskReviewRejectStatus();
        $inprogressStatus = StatusService::getInstance()->getTaskDefaultStartStatus();
        $remakeStatus = StatusService::getInstance()->getTaskDefaultRemakeStatus();

        $needRepairStatusIdList = [$reviewing['id'], $partyAReviewing['id'], $publishStatus['id'], $doneStatus['id'], $waitPartyBSubmitStatus['id']];
//        $notStartStatusIdList = array_column(StatusService::getInstance()->getNotStartedStatus(), 'id');
        $inProgressStatusIdList = [$reviewedStatus['id'], $inprogressStatus['id'], $remakeStatus['id']];

//        $canRepairReasonTypeList = [
//            NoteModel::REASON_TYPE_DEMAND_CHANGE,
//            NoteModel::REASON_TYPE_BASIC_QUALITY,
//            NoteModel::REASON_TYPE_PROJECT_QUALITY,
//        ];
        $draftStatus = StatusService::getInstance()->getDefaultDraftStatus();
        $taskRepairOrderService = TaskRepairOrderService::getInstance();
        $noteModel = model(NoteModel::class);

        foreach ($paramEntityIdList as $ei => $entityId) {
            $res[$ei] = [
                'entity_id' => $entityId,
                'err_code' => 0,
                'err_msg' => 'OK',
            ];

            $currentTotalEntityIdList = $realEntityList[$entityId] ?? [];

            if (empty($entityList[$entityId])) {
                $res[$ei]['err_code'] = ErrorCode::ENTITY_NOT_FOUND;
                $res[$ei]['err_msg'] = '实体不存在';
                continue;
            }
            $entity = $entityList[$entityId];
            // 修改实体
            if (empty($reviewFeedbackEntityList[$entityId])) {
                $res[$ei]['err_code'] = ErrorCode::REVIEW_FEEDBACK_ENTITY_NOT_FOUND;
                $res[$ei]['err_msg'] = '反馈实体不存在';
                continue;
            }

            $reviewFeedbackEntity = $reviewFeedbackEntityList[$entityId];

            if ($reviewFeedbackEntity['published'] === ReviewFeedbackEntityModel::PUBLISHED_YES) {
                $res[$ei]['err_code'] = ErrorCode::REVIEW_FEEDBACK_ENTITY_ALREADY_PUBLISHED;
                $res[$ei]['err_msg'] = '反馈实体已经发布过';
                continue;
            }

            $entityJson = json_decode($entity['json'], true);
            $status = $entityJson[$moduleCode . '_status'] ?? 0;
            $isDraft = $status == $draftStatus['id'];

            $noteModel->startTrans();
            try {
                // 处理实体发布
                $enntityPublishInfo = $this->handleReviewFeedbackEntityPublish(
                    $reviewFeedbackEntity, $entity, $stepCategoryTaskDefaultValueMap, $episodeCodeIdMap
                );

                // 获取发布实体时生成的任务ID，更新【标准排期时间】，并记录标准排期来源
                $enntityPublishGeneratedTask = array_map(fn($item) => ($item['asset_task_published']['added'] ?? $item['added'] ?? []), $enntityPublishInfo);
                $enntityPublishGeneratedTask = array_unique(array_merge(...array_values($enntityPublishGeneratedTask)));
                $this->dealDemandPublishEntityGeneratedTaskStandardPlanTime($reviewFeedbackId, $enntityPublishGeneratedTask);

                //处理环节需求与返修
                $noteGroupedByStepCategory = $noteGrouped[$entityId] ?? [];

                //需求实体有需求的环节id
                $noteEntityStepCategoryIdList = $noteEntityStepCategoryIds[$entityId] ?? [];
                //处理需求发布实体任务计划时间 (只针对有需求新增和启用的任务)
                $this->dealDemandPublishEntityTaskPlanTime(
                    $reviewFeedbackId, $reviewFeedbackEntity, $noteEntityStepCategoryIdList,
                    $stepCategoryTaskDefaultValueMap, $currentTotalEntityIdList, $stepCategoryIds, $planMap
                );
                $updateDemandStatusToFinalNoteIdList = [];
                $updateDemandStatusToFinalDemandTypeToFeedbackNoteIdList = [];
                foreach ($noteGroupedByStepCategory as $stepCategoryId => $noteGroupedByReasonType) {
                    $k = $entityId . '#' . $stepCategoryId;
                    $entityStepCategoryTaskList = $entityTaskList[$k] ?? [];
                    if (empty($entityStepCategoryTaskList) && isset($entityDownstreamEntityMap[$entityId])) {
                        $k = $entityDownstreamEntityMap[$entityId] . '#' . $stepCategoryId;
                        $entityStepCategoryTaskList = $entityTaskList[$k] ?? [];
                    }
                    $entityStepCategoryTaskList = array_column($entityStepCategoryTaskList, null, 'step_id');
                    // 找出这个环节下需要返修的反馈 task_id=> [note_id,note_id]
                    $stepCategoryNoteNeedRepairRelation = [];
                    foreach ($noteGroupedByReasonType as $reasonType => $stepCategoryReasonNoteList) {
//                        $isCanRepairReasonType = in_array($reasonType, $canRepairReasonTypeList);
                        foreach ($stepCategoryReasonNoteList as $stepCategoryReasonNote) {
                            // 查询这个任务能否返修
                            /**
                             * 1. 不是废除
                             * 2. 不是草稿
                             * 3. 是可以返修的类型
                             * 4. 返修工序大于0
                             * 5. 要返修的工序任务是可返修状态
                             */
                            if ($reviewFeedbackEntity['enable'] != ReviewFeedbackEntityModel::ENABLE_NO
                                && !$isDraft
//                                && $isCanRepairReasonType
                                && $stepCategoryReasonNote['repair_step_id'] > 0
                                && !empty($entityStepCategoryTaskList[$stepCategoryReasonNote['repair_step_id']])
                            ) {
                                /**
                                 * 1. 可以返修的去进行返修
                                 * 2. 进行中的修改为反馈类型 并且修改为完成状态
                                 * 3. 未开始的直接修改为需求 并且修改为完成状态
                                 */
                                if (in_array($entityStepCategoryTaskList[$stepCategoryReasonNote['repair_step_id']]['task_status'], $needRepairStatusIdList)) {
                                    // 可返修状态
                                    $stepCategoryNoteNeedRepairRelation[$entityStepCategoryTaskList[$stepCategoryReasonNote['repair_step_id']]['id']][] = $stepCategoryReasonNote['id'];
                                } elseif (in_array($entityStepCategoryTaskList[$stepCategoryReasonNote['repair_step_id']]['task_status'], $inProgressStatusIdList)) {
                                    // 进行中
                                    $updateDemandStatusToFinalDemandTypeToFeedbackNoteIdList[] = $stepCategoryReasonNote['id'];
                                } else {
                                    // 剩余都是未开始了
                                    $updateDemandStatusToFinalNoteIdList[] = $stepCategoryReasonNote['id'];
                                }
                            } else {
                                // 工序不存在 或者没填写工序 直接变成需求
                                $updateDemandStatusToFinalNoteIdList[] = $stepCategoryReasonNote['id'];
                            }
                        }
                    }

                    // 发起返修
                    foreach ($stepCategoryNoteNeedRepairRelation as $needRepairTaskId => $stepCategoryRepairNoteIdList) {

                        // 比较每个需求 得出不需要返修的环节的交集 才是真正不需要返修的环节
                        $taskDontRepairStepCategoryList = [];
                        foreach ($stepCategoryRepairNoteIdList as $noteId) {
                            if (isset($downstreamDontRepairStepCategoryIdListGrouped[$noteId])) {
                                $taskDontRepairStepCategoryList[] = $downstreamDontRepairStepCategoryIdListGrouped[$noteId];
                            }
                        }
                        if (count($taskDontRepairStepCategoryList) > 1) {
                            $taskDontRepairStepCategoryList = array_intersect(...$taskDontRepairStepCategoryList);
                        } else if (count($taskDontRepairStepCategoryList) === 1) {
                            $taskDontRepairStepCategoryList = $taskDontRepairStepCategoryList[0];
                        }

                        $taskRepairOrderRes = $taskRepairOrderService->start(['task_id' => $needRepairTaskId, 'need_repair_task_id' => $needRepairTaskId, 'note_id' => $stepCategoryRepairNoteIdList, 'dont_repair_step_category' => $taskDontRepairStepCategoryList], $userId, true);
                        APP_DEBUG && trace("发起返修结果", 'DEBUG');
                        APP_DEBUG && trace(var_export($taskRepairOrderRes, true), 'DEBUG');
                        // 发起返修成功 修改为进行中状态 关联返修单
                        if (!empty($taskRepairOrderRes['task_repair_order']['id'])) {
                            model(NoteModel::class)
                                ->where(['id' => ['IN', implode(',', $stepCategoryRepairNoteIdList)]])
                                ->save([
                                    'demand_type' => NoteModel::DEMAND_TYPE_REVIEW_FEEDBACK,
                                    'demand_status' => NoteModel::DEMAND_STATUS_PROCESSING,
                                    'task_repair_order_id' => $taskRepairOrderRes['task_repair_order']['id'],
                                ]);
                        } else {
                            // 修改为审核反馈类型
                            model(NoteModel::class)
                                ->where(['id' => ['IN', implode(',', $stepCategoryRepairNoteIdList)]])
                                ->save(['demand_type' => NoteModel::DEMAND_TYPE_REVIEW_FEEDBACK]);
                        }
                    }
                    if (!empty($updateDemandStatusToFinalNoteIdList)) {
                        // 修改需求为完成状态 并且需求类型为需求
                        model(NoteModel::class)
                            ->where(['id' => ['IN', implode(',', $updateDemandStatusToFinalNoteIdList)]])
                            ->save(['demand_status' => NoteModel::DEMAND_STATUS_FINAL, 'demand_type' => NoteModel::DEMAND_TYPE_DEMAND]);
                    }
                    if (!empty($updateDemandStatusToFinalDemandTypeToFeedbackNoteIdList)) {
                        // 修改需求为完成状态 并且需求类型为反馈
                        model(NoteModel::class)
                            ->where(['id' => ['IN', implode(',', $updateDemandStatusToFinalDemandTypeToFeedbackNoteIdList)]])
                            ->save(['demand_status' => NoteModel::DEMAND_STATUS_FINAL, 'demand_type' => NoteModel::DEMAND_TYPE_FEEDBACK]);
                    }
                }
                $noteModel->commit();
            } catch (HttpResponseException $e) {
                $noteModel->rollback();
                $eData = $e->getResponse()->getData();
                $res[$ei]['err_code'] = $eData['code'];
                $res[$ei]['err_msg'] = $eData['msg'];
                APP_DEBUG && trace(var_export($eData, true), 'ERR');
                APP_DEBUG && trace(format_exception_info($e), 'ERR');
            } catch (Throwable $e) {
                $noteModel->rollback();
                $res[$ei]['err_code'] = $e->getCode();
                $res[$ei]['err_msg'] = $e->getMessage();
                APP_DEBUG && trace(format_exception_info($e), 'ERR');
                continue;
            }
        }

        $hookData = array_merge($hookData, []);
        Hook::listen('demand_order_publish', $hookData);

        return $res;
    }

    /**
     * 获得模块可保存自定义字段
     * @param $code
     * @return string[]
     */
    private function getModuleCanSaveFields($code)
    {
        $res = [];
        switch ($code) {
            case 'design':
                $res = [
                    'review_feedback_entity_hair_making' => 'design_hair_making', // 毛发制作
                    'review_feedback_entity_production_method' => 'design_production_method', // 制作方式
                    'review_feedback_entity_fx_production' => 'design_fx_production', // 特效制作
                ];
                break;
            case 'storyboard':
                $res = [
                    'review_feedback_entity_cloth_solution' => 'storyboard_cloth_solution', // 布料解算
                    'review_feedback_entity_fx' => 'storyboard_fx', // 特效方式
                    'review_feedback_entity_comp_type' => 'storyboard_comp_type', // 合成方式
                ];
                break;
            default:
        }
        return $res;
    }

    /**
     * 检查审核反馈是否还存在 未确认,待发布的需求和实体
     * @param $reviewFeedbackId
     * @return bool
     */
    public function isAllPublished($reviewFeedbackId)
    {
        $notPublishedEntity = model(ReviewFeedbackEntityModel::class)
            ->forceMasterDB()
            ->alias('rfe')
            ->join('entity e on e.id = rfe.entity_id')
            ->where(['rfe.review_feedback_id' => $reviewFeedbackId, 'rfe.published' => 'no'])
            ->field('rfe.id')
            ->find();

        return empty($notPublishedEntity);
    }

    /**
     * 处理实体信息的发布
     * @param $reviewFeedbackEntity
     * @param $entity
     * @param $stepCategoryTaskDefaultValueMap
     * @param $episodeCodeIdMap
     * @return void
     * @throws Exception
     * @throws Throwable
     */
    private function handleReviewFeedbackEntityPublish($reviewFeedbackEntity, $entity, $stepCategoryTaskDefaultValueMap, $episodeCodeIdMap)
    {
        $reviewFeedbackEntity['json'] = json_decode($reviewFeedbackEntity['json'], true);
        $entityModule = module_by_id($entity['module_id']);
        $reviewFeedbackEntityPlanDeliveryTime = $reviewFeedbackEntity['json']['plan_delivery_time'] ?? [];
        $stepCategoryTaskDefaultValueMap = $this->mergeEntityAndStepCategoryPlanDeliveryTime($episodeCodeIdMap[$entity['initial_episode_code']] ?? 0, $stepCategoryTaskDefaultValueMap, $reviewFeedbackEntityPlanDeliveryTime);
        request()->getModuleCode($entityModule['code']);
        $baseJson = $entityJson = json_decode($entity['json'], true);
        // 先把草稿数据放进来
        if (isset($reviewFeedbackEntity['json']['review_feedback_entity_draft_data'])) {
            foreach ($reviewFeedbackEntity['json']['review_feedback_entity_draft_data'] as $dk => $dv) {
                if (empty($dv)) {
                    continue;
                }
                if (in_array($dk, ['design_category', 'initial_episode_code', 'showings_number', 'name'])) {
                    // 不允许修改资产类型
                    continue;
                }
                $baseJson[$dk] = $dv;
            }
        }

        if ($reviewFeedbackEntity['is_append'] === 'yes') {
            $baseJson['is_append'] = 'yes';
        }

        // 写入指定的属性对应的自定义字段
        foreach ($this->getModuleCanSaveFields($entityModule['code']) as $sourceField => $targetField) {
            if (!empty($reviewFeedbackEntity['json'][$sourceField])) {
                $baseJson[$targetField] = $reviewFeedbackEntity['json'][$sourceField];
            }
        }
        $baseJson['id'] = $entity['id'];
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();

        $entityCommonService = CommonService::instance('entity');
        $entityCommonService->update($baseJson, $entityModule['code'], false);

        // 概念模块 剧集场次不一致 添加关联关系
        if (
            $entityModule['code'] === 'design' &&
            ($reviewFeedbackEntity['initial_episode_code'] !== $entity['initial_episode_code'] ||
                $reviewFeedbackEntity['showings_number'] !== $entity['showings_number'])
        ) {
            $newEntity = $entityCommonService->find([
                'param' => [
                    'filter' => [
                        'id' => $entity['id'],
                    ],
                ],
            ], 'design');
            $newEntity['initial_episode_code'] = $reviewFeedbackEntity['initial_episode_code'];
            $newEntity['showings_number'] = $reviewFeedbackEntity['showings_number'];
            EntityService::getInstance()->designMultiEpisodeCreateCheck([
                'old' => $entity,
                'new' => $newEntity,
            ]);
        }
        // 废除/启用实体
        if ($reviewFeedbackEntity['enable'] !== 'default') {
            // 检查当前实体和需求单实体的启用废除状态是否一致
            $statusField = $entityModule['code'] . '_status';
            $reviewFeedbackEntityDisabled = $reviewFeedbackEntity['enable'] === 'no';
            $entityCurrentDisabled = !empty($entityJson[$statusField]) && $entityJson[$statusField] == $closedStatus['id'];
            // 不一致进行启用废除操作
            if ($reviewFeedbackEntityDisabled !== $entityCurrentDisabled) {
                $enableStatus = $reviewFeedbackEntity['enable'] === 'yes' ? 'Ena' : 'Abo';
                $enableData = [
                    'id' => $entity['id'],
                    'status' => $enableStatus,
                ];

                $eae = EntityAbolitionOrEnableService::getInstance()->entityAbolitionOrEnabling($enableStatus, $enableData);
//                if ($entityModule['code'] === 'design') {
                //                    $eae = TaskService::getInstance()->TaskAbolitionOrEnabling($enableStatus, $enableData);
                //                } else {
                //                    $eae = ShotService::getInstance()->shotAbolitionOrEnabling($enableStatus, $enableData);
                //                }
                APP_DEBUG && trace("废除/启用实体结果", 'DEBUG');
                APP_DEBUG && trace(var_export($eae, true), 'DEBUG');
            }
        }
        // 发布
        $resPublish = [];
        if (in_array($reviewFeedbackEntity['enable'], ['default', 'yes'])) {
            $prs = EntityService::getInstance()->publish(['id' => $entity['id']], $entityModule['code'], $entity['tenant_id'], 'task_generated', '', $stepCategoryTaskDefaultValueMap);
            $resPublish = $prs;
            APP_DEBUG && trace("发布实体结果", 'DEBUG');
            APP_DEBUG && trace(var_export($prs, true), 'DEBUG');
        }
        // 实体操作结束 修改为实体已经发布完成
        model(ReviewFeedbackEntityModel::class)->modifyItem(['id' => $reviewFeedbackEntity['id'], 'published' => 'yes', 'published_time' => time()]);
        return $resPublish;
    }

    /**
     * 删除需求单
     * @param $filter
     * @return array
     * @throws Throwable
     */
    public function deleteDemandOrder($filter)
    {
        $reviewFeedbackModel = model(ReviewFeedbackModel::class);
        $reviewFeedbackList = $reviewFeedbackModel
            ->where($filter)
            ->field("id,status")
            ->select();
        if (empty($reviewFeedbackList)) {
            return [];
        }

        $reviewFeedbackIds = [];
        foreach ($reviewFeedbackList as $reviewFeedbackItem) {
            if ($reviewFeedbackItem['status'] != ReviewFeedbackModel::STATUS_NOT_STARTED) {
                throw new LogicException('review feedback already started', ErrorCode::REVIEW_FEEDBACK_ALREADY_STARTED);
            }
            $reviewFeedbackIds[] = $reviewFeedbackItem['id'];
        }

        $note = model(NoteModel::class)->where([
            'review_feedback_id' => ['IN', $reviewFeedbackIds],
            'demand_status' => ["IN", NoteModel::REPAIRED_DEMAND_STATUS],
        ])->find();

        if (!empty($note)) {
            throw new LogicException('review feedback already started', ErrorCode::REVIEW_FEEDBACK_ALREADY_STARTED);
        }
        $noteList = model(NoteModel::class)
            ->where(['review_feedback_id' => ['IN', $reviewFeedbackIds]])
            ->field("id")
            ->select();
        $noteIds = array_column($noteList, "id");

        $relationNoteEntityRelationIds = [];
        $noteEntityRelationIds = [];
        if (!empty($noteIds)) {
            //删除关联关系
            $noteEntityRelationList = model(NoteEntityRelationModel::class)
                ->where(['note_id' => ["IN", $noteIds]])
                ->field("id")
                ->select();

            if (!empty($noteEntityRelationList)) {
                $noteEntityRelationIds = array_column($noteEntityRelationList, "id");
                $relationNoteEntityRelationList = model(RelationNoteEntityRelationModel::class)
                    ->where(['note_entity_relation_id' => ["IN", $noteEntityRelationIds]])
                    ->field("id")
                    ->select();
                //删除影响的镜头
                $relationNoteEntityRelationIds = array_column($relationNoteEntityRelationList, "id");
            }
        }

        //删除影响的镜头关联关系
        $res = [];
        $reviewFeedbackModel->startTrans();
        try {
            if (!empty($relationNoteEntityRelationIds)) {
                $res['relation_note_entity_relation'] = model(RelationNoteEntityRelationModel::class)->where(["id" => ["IN", $relationNoteEntityRelationIds]])->delete();
            }

            //删除关联关系
            if (!empty($noteEntityRelationIds)) {
                $res['note_entity_relation'] = model(NoteEntityRelationModel::class)
                    ->where(["id" => ["IN", $noteEntityRelationIds]])
                    ->delete();
            }
            if (!empty($noteIds)) {
                $res['note'] = model(NoteModel::class)->where(['id' => ['IN', $noteIds]])->delete();
            }

            if (!empty($reviewFeedbackIds)) {
                $res['demand_order'] = model(ReviewFeedbackModel::class)->where(['id' => ['IN', $reviewFeedbackIds]])->delete();
            }
            $reviewFeedbackModel->commit();
            return $res;
        } catch (Throwable $e) {
            $reviewFeedbackModel->rollback();
            throw $e;
        }
    }

    /**
     * 批量修改需求单条目
     * @param $data
     * @return int
     * @throws Exception
     */
    public function batchUpdateSameNote($data)
    {
        $noteList = model(NoteModel::class)->where(["id" => ["IN", $data["id"]]])->select();
        if (empty($noteList)) {
            return [];
        }

        //若传入note跨需求单，中断
        $noteReviewFeedbackIds = array_column($noteList, 'review_feedback_id');
        if (count(array_unique($noteReviewFeedbackIds)) !== 1) {
            throw new LogicException('note_id across multi demand order', ErrorCode::RESULT_ACROSS_MULTI_SET);
        }
        $note = array_shift($noteList);

        //权限验证
        $this->findDemandOrderPermissionsDeal($note['review_feedback_id'], "confirm_demand_order_note", function () use ($data) {
            return isset($data["demand_status"]) || isset($data["accept_changes"]);
        });

        //TODO 需求单类型同样需要处理
        //验证判定 (如果有返修中和返修完成的,将不能改变状态)
        if (isset($data["demand_status"]) || isset($data["accept_changes"])) {
            if (in_array($note['demand_status'], NoteModel::REPAIRED_DEMAND_STATUS)) {
                throw new LogicException('note repair has been initiated', ErrorCode::NOTE_REPAIR_HAS_BEEN_INITIATED);
            }

            if (isset($data["accept_changes"])) {
                $data["demand_status"] = $data["accept_changes"];
                unset($data["accept_changes"]);
            }
        }

        $instance = CommonService::instance("note");
        $instance->setCurrentModuleCode("note");
        $resData = $instance->commonBatchUpdateSame($data, module_by_code("note"));
        return $resData;
    }

    /**
     * 批量移除需求单未发布实体，及相关条目
     * @param $data
     * @return array
     * @throws Throwable
     */
    public function batchRemoveUnpublishedEntity($data)
    {
        // 仅需求单需要移除，审核反馈无需操作
        // 未发布的review_feedback_entity
        $reviewFeedbackEntityModel = model(ReviewFeedbackEntityModel::class);
        $reviewFeedbackEntityList = $reviewFeedbackEntityModel
            ->where([
                "id" => ["IN", $data["id"]],
                "published" => "no",
            ])
            ->select();

        $reviewFeedbackEntityIds = array_column($reviewFeedbackEntityList, 'id');

        // 若传入review_feedback_entity存在无效id，中断
        $invalidReviewFeedbackEntityIds = array_filter($data['id'], function ($reviewFeedbackEntityId) use ($reviewFeedbackEntityIds) {
            return !in_array($reviewFeedbackEntityId, $reviewFeedbackEntityIds);
        });
        if (!empty($invalidReviewFeedbackEntityIds)) {
            throw new LogicException('not removable entity_id exist', ErrorCode::RESULT_NOT_OPERABLE_EXIST);
        }

        // 若传入review_feedback_entity跨需求单，中断
        $reviewFeedbackIds = array_column($reviewFeedbackEntityList, 'review_feedback_id');
        if (count(array_unique($reviewFeedbackIds)) !== 1) {
            throw new LogicException('entity_id across multi demand order', ErrorCode::RESULT_ACROSS_MULTI_SET);
        }
        $reviewFeedbackId = array_shift($reviewFeedbackIds);

        $draftStatus = StatusService::getInstance()->getDefaultDraftStatus();
        $moduleCodeMap = model(ModuleModel::class)->field('id, code')->select();
        $moduleCodeMap = array_combine(array_column($moduleCodeMap, 'id'), $moduleCodeMap);

        $entityIds = array_column($reviewFeedbackEntityList, 'entity_id');
        $noteIds = [];
        $noteRelationIds = [];
        $relationNoteRelationIds = [];
        if (!empty($entityIds)) {
            // 查所有需求关系
            // entity_id 查 note_entity_relation
            $noteList = model(NoteEntityRelationModel::class)
                ->where([
                    'entity_id' => ['IN', $entityIds],
                    'review_feedback_id' => $reviewFeedbackId,
                ])
                ->field('id, note_id')
                ->select();
            $noteIds = array_column($noteList, 'note_id');
            $noteRelationIds = array_column($noteList, 'id');

            // entity_id 查 relation_note_entity_relation
            if (!empty($noteRelationIds)) {
                $relationNoteRelationList = model(RelationNoteEntityRelationModel::class)
                    ->where([
                        'note_entity_relation_id' => ['IN', $noteRelationIds],
                    ])
                    ->field('id')
                    ->select();
                $relationNoteRelationIds = array_column($relationNoteRelationList, 'id');
            }

            // 查草稿实体
            $entityList = model(EntityModel::class)
                ->where(['id' => ['IN', $entityIds]])
                ->field("id, module_id, json")
                ->select();
            $entityList = array_filter($entityList, function ($entity) use ($moduleCodeMap, $draftStatus) {
                $moduleCode = $moduleCodeMap[$entity['module_id']]['code'] ?? null;
                if (empty($moduleCode)) {
                    return false;
                }
                $entityJson = json_decode($entity['json'], true);
                return isset($entityJson["${moduleCode}_status"]) && ($entityJson["${moduleCode}_status"] == $draftStatus['id']);
            });
            $entityIds = array_column($entityList, 'id');
        }

        $res = [];
        $reviewFeedbackEntityModel->startTrans();
        try {
            if (!empty($relationNoteRelationIds)) {
                $res['relation_note_entity_relation'] = model(RelationNoteEntityRelationModel::class)
                    ->where(['id' => ['IN', $relationNoteRelationIds]])
                    ->delete();
            }
            if (!empty($noteRelationIds)) {
                $res['note_entity_relation'] = model(NoteEntityRelationModel::class)
                    ->where(['id' => ['IN', $noteRelationIds]])
                    ->delete();
            }
            if (!empty($noteIds)) {
                $res['note_record'] = model(NoteRecordModel::class)
                    ->where(['note_id' => ['IN', $noteIds]])
                    ->delete();
                $res['note'] = model(NoteModel::class)
                    ->where(['id' => ['IN', $noteIds]])
                    ->delete();

                // 删除需求和工单的标签关联关系
                $res['tag_relation'] = model(TagRelationModel::class)
                    ->where(['relation_id' => ['IN', $noteIds], 'relation_type' => ['IN', [TagRelationModel::RELATION_TYPE_DEMAND, TagRelationModel::RELATION_TYPE_WORK_ORDER]]])
                    ->delete();
            }
            if (!empty($reviewFeedbackEntityIds)) {
                $res['review_feedback_entity'] = model(ReviewFeedbackEntityModel::class)
                    ->where(['id' => ['IN', $reviewFeedbackEntityIds]])
                    ->delete();
            }
            if (!empty($entityIds)) {
                $res['entity'] = model(EntityModel::class)
                    ->where(['id' => ['IN', $entityIds]])
                    ->delete();
            }
            $reviewFeedbackEntityModel->commit();
            return $res;
        } catch (Throwable $e) {
            $reviewFeedbackEntityModel->rollback();
            throw $e;
        }
    }

    /**
     * 获取需求单权限处理
     * @param      $demandOrderId
     * @param      $filter
     * @param null $dealFun
     */
    public function findDemandOrderPermissionsDeal($demandOrderId, $filter, $dealFun = null)
    {
        if (empty($demandOrderId)) {
            return;
        }
        $demandOrder = model(ReviewFeedbackModel::class)->find($demandOrderId);
        if (!in_array($demandOrder['demand_type'], [ReviewFeedbackModel::DEMAND_TYPE_REVIEW_FEEDBACK, ReviewFeedbackModel::DEMAND_TYPE_DEMAND_ORDER])) {
            return;
        }
        $currentPermissions = $demandOrder['permissions'];
        $this->demandOrderPermissionsDeal($currentPermissions, $filter, $dealFun);
    }

    /**
     * 处理需求单权限
     * @param               $currentPermissions
     * @param               $filter
     * @param callable|null $dealFun
     */
    public function demandOrderPermissionsDeal($currentPermissions, $filter, callable $dealFun = null)
    {
        if ($currentPermissions == ReviewFeedbackModel::PERMISSIONS_OFF) {
            $this->demandOrderPermissionsCompare($currentPermissions, []);
        }

        //外部条件,如有条件则不通过
        if (isset($dealFun) && !$dealFun()) {
            return;
        }

        switch ($filter) {
            case "delete_demand_order":
            case "entry_demand_order_note":
            case "delete_feedback_note":
            case "entry_review_feedback_note": //录入审核反馈
                $this->demandOrderPermissionsCompare($currentPermissions, [ReviewFeedbackModel::PERMISSIONS_ON, ReviewFeedbackModel::PERMISSIONS_ONE]);
                break;
            case "send_repair":
            case "confirm_demand_order_note": //确认需求单
            case "confirm_review_feedback_note": //确认审核反馈(仅兼容用)
                $this->demandOrderPermissionsCompare($currentPermissions, [ReviewFeedbackModel::PERMISSIONS_ON, ReviewFeedbackModel::PERMISSIONS_TWO]);
                break;
        }
    }

    /**
     * 需求单权限比较
     * @param $currentPermissions
     * @param $needPermissionsList
     */
    public function demandOrderPermissionsCompare($currentPermissions, $needPermissionsList)
    {
        if (!in_array($currentPermissions, $needPermissionsList)) {
            throw new LogicException("review feedback permissions insufficient", ErrorCode::REVIEW_FEEDBACK_PERMISSIONS_INSUFFICIENT);
        }
    }

    /**
     * 接受所有待确认需求
     * @param int $reviewFeedbackId
     * @param int $userId
     * @return void
     * @throws \Exception
     */
    public function acceptAll(int $reviewFeedbackId, int $userId)
    {
        $noteList = model(NoteModel::class)
            ->where(['review_feedback_id' => $reviewFeedbackId, 'demand_status' => NoteModel::DEMAND_STATUS_DEFAULT])
            ->select();
        if (!empty($noteList)) {
            $noteIdList = array_column($noteList, 'id');
            model(NoteModel::class)
                ->where(['id' => ['IN', $noteIdList]])
                ->save(['demand_status' => NoteModel::DEMAND_STATUS_PENDING, 'confirm_user_id' => $userId]);
        }
    }

    /**
     * 记录标准排期到任务
     * @param $reviewFeedbackId
     * @param $taskIdList
     * @return void
     */
    public function dealDemandPublishEntityGeneratedTaskStandardPlanTime($reviewFeedbackId, $taskIdList = [])
    {
        $taskList = model(TaskModel::class)
            ->where(["id" => ['IN', implode(',', $taskIdList)]])
            ->field("id,plan_delivery_time,standard_plan_time,standard_plan_id")->select();
        if (empty($taskList)) {
            return;
        }
        $updateData = [];
        foreach ($taskList as $taskItem) {
            // 需求单ID
            $tmp = [
                'id' => $taskItem['id'],
                'standard_plan_id' => $reviewFeedbackId,
                'standard_plan_time' => 0
            ];
            // 计划交付时间 -> 标准排期时间
            if (!empty($taskItem['plan_delivery_time'])) {
                $tmp['standard_plan_time'] = (int)$taskItem['plan_delivery_time'];
            }
            //是否有变更
            if (empty(array_diff_assoc($tmp, $taskItem))) {
                continue;
            }
            $updateData[] = $tmp;
        }
        if (empty($updateData)) {
            return;
        }
        model(TaskModel::class)->saveAll($updateData);
    }

    /**
     * 处理需求发布实体任务计划时间
     * @param $reviewFeedbackEntity
     * @param $noteEntityStepCategoryIdList
     * @param $stepCategoryTaskDefaultValueMap
     * @param $totalEntityIdList
     * @param $stepCategoryIds
     * @param $planMap
     * @return void|null
     */
    public function dealDemandPublishEntityTaskPlanTime($reviewFeedbackId, $reviewFeedbackEntity, $noteEntityStepCategoryIdList, $stepCategoryTaskDefaultValueMap, $totalEntityIdList, $stepCategoryIds, $planMap)
    {
        // 是否是更新所有
        $isSaveAll = 0;
        //是否新增和废除
        $noteStepCategoryIds = [];
        $reviewFeedbackEntityJson = json_decode($reviewFeedbackEntity['json'], true);
        $reviewFeedbackEntityPlanDeliveryTime = $reviewFeedbackEntityJson['plan_delivery_time'] ?? [];

        // 判断：新增需求 或 启用需求
        if ($reviewFeedbackEntity['is_append'] == 'yes' || $reviewFeedbackEntity['enable'] == 'yes') {
            $isSaveAll = 2; // 2: 新增需求或启用需求
        } elseif (!empty($noteEntityStepCategoryIdList)) { // 是否有需求
            $isSaveAll = 1; // 1: 环节是否有需求
            $noteStepCategoryIds = array_keys($noteEntityStepCategoryIdList);
        }

        //没有修改 ,或者没有默认的设置时间
        if (empty($isSaveAll) || (empty($stepCategoryTaskDefaultValueMap) && empty($reviewFeedbackEntityPlanDeliveryTime))) {
            return;
        }
        $stepCategoryIds = array_unique(array_merge($stepCategoryIds, array_keys($reviewFeedbackEntityPlanDeliveryTime)));
        $taskList = model(TaskModel::class)
            ->where(["entity_id" => ['IN', implode(',', $totalEntityIdList)], 'step_type' => 'step', "step_category_id" => ["IN", $stepCategoryIds]])
            ->field("id,step_category_id,episode_id,project_id,plan_delivery_time,plan_end_time,episode_id")->select();

        if (empty($taskList)) {
            return;
        }

        $updateData = [];
        $delayData = [];
        foreach ($taskList as $taskItem) {
            //如果不存在,不修改计划交付时间
            $currentChangePlanEndTime = empty($reviewFeedbackEntityPlanDeliveryTime[$taskItem['step_category_id']]) ?
                ($stepCategoryTaskDefaultValueMap[$taskItem['episode_id']][$taskItem['step_category_id']]['plan_end_time'] ?? 0) :
                $reviewFeedbackEntityPlanDeliveryTime[$taskItem['step_category_id']];

            if (empty($currentChangePlanEndTime)) {
                continue;
            }

            $tmp = [
                'plan_end_time' => $currentChangePlanEndTime,
                'plan_delivery_time' => $taskItem['plan_delivery_time'],
            ];

            //如果不存在计划完成时间或者需求单上默认的排期时间超过了计划时间
            if (!isset($planMap[$taskItem['episode_id'] . '#' . $taskItem['step_category_id']]) ||
                $currentChangePlanEndTime > $planMap[$taskItem['episode_id'] . '#' . $taskItem['step_category_id']]['end_time']) {
                $tmp['plan_delivery_time'] = $currentChangePlanEndTime;
            }
            // 用需求单上的排期时间 更新标准排期时间
            $tmp['standard_plan_time'] = $currentChangePlanEndTime;
            $tmp['standard_plan_id'] = $reviewFeedbackId;
            //是否有变更
            if (empty(array_diff_assoc($tmp, $taskItem))) {
                continue;
            }
            // 只要有新增、启用需求或环节需求,就【按集和环节】创建延期单
            if ($isSaveAll == 2 || ($isSaveAll == 1 && in_array($taskItem['step_category_id'], $noteStepCategoryIds))) { // 20231114修改：无需求单存在实体的交付时间就不创建延期单  ##|| !empty($reviewFeedbackEntityPlanDeliveryTime[$taskItem['step_category_id']])
                $tmp['id'] = $taskItem['id'];
                $updateData[] = $tmp;
                $delayData[$taskItem['episode_id']][$taskItem['step_category_id']][] = [
                    'task_id' => $taskItem['id'],
                    'original_plan_time' => $taskItem['plan_end_time'],
                    'plan_delivery_time' => $taskItem['plan_delivery_time'],
                    'delay_time' => $tmp['plan_end_time'],
                    'type' => DelayOrderTaskModel::TYPE_DEMAND_ORDER,
                ];
            }
        }
        if (empty($updateData)) {
            return;
        }

        //有排期变化的任务，通过延期单记录
        foreach ($delayData as $episodeId => $delayDatum) {
            foreach ($delayDatum as $stepCategoryId => $item) {
                $currentData = [
                    "episode_id" => $episodeId,
                    "step_category_id" => $stepCategoryId,
                    "delay_task_list" => $item,
                    "review_feedback_id" => $reviewFeedbackId,
                ];
                Client::send("create_delay_order", build_queue_data_with_xu($currentData));
            }
        }
        model(TaskModel::class)->saveAll($updateData);
    }

    /**
     * 获取需求实体计划数据
     * @param $paramEntityIdList
     * @param $reviewFeedback
     * @return array
     */
    public function getDemandEntityPlanData($paramEntityIdList, $reviewFeedback)
    {
        $entityIds = array_values($paramEntityIdList);
        $entityList = model(EntityModel::class)->where(["id" => ["IN", $entityIds]])->select();
        $episodeCodes = [];
        $entityFilter = [];
        $baseFilter = [
            'project_id' => $reviewFeedback['project_id'],
        ];
        $fields = ['id'];

        // 根据实体类型 分别组装 资产、镜头 filter
        $entityAssetFilter = [];
        $entityShotFilter = [];
        $assetModuleIdList = [
            module_by_code('asset')['id'],
            module_by_code('design')['id'],
            module_by_code('level')['id']
        ];
        foreach ($entityList as &$entityItem) {
            if (in_array($entityItem['module_id'], $assetModuleIdList)) {
                $episodeCodes[$entityItem['initial_episode_code']] = $entityItem['initial_episode_code'];
                $entityAssetFilter[] = ['entity.code' => $entityItem['code']];
                $entityItem['unique_k'] = $entityItem['code'];
            } else {
                $episodeCodes[$entityItem['initial_episode_code']] = $entityItem['initial_episode_code'];
                $entityShotFilter[] = [
                    'entity.initial_episode_code' => $entityItem['initial_episode_code'],
                    'entity.showings_number' => $entityItem['showings_number'],
                    'entity.code' => $entityItem['code'],
                ];
                $entityItem['unique_k'] = sprintf("%s/%s/%s", $entityItem['initial_episode_code'], $entityItem['showings_number'], $entityItem['code']);
            }
        }
        $entityFilter = array_merge($entityAssetFilter, $entityShotFilter);

        // 合并 module_id 查询
        $baseModuleFilter = [];
        if (!empty($entityAssetFilter)) {
            $baseModuleFilter = $assetModuleIdList;
        }
        if (!empty($entityShotFilter)) {
            $baseModuleFilter[] = module_by_code('shot')['id'];
            $baseModuleFilter[] = module_by_code('storyboard')['id'];
        }
        if (!empty($baseModuleFilter)) {
            $baseFilter['module_id'] = ['IN', $baseModuleFilter];
        }

        // 合并uk逻辑
        $fields[] = "if(find_in_set(module_id, '" . implode(',', $assetModuleIdList) . "') > 0, code, concat(initial_episode_code,'/',showings_number,'/',code)) as unique_k";

        if (count($entityFilter) === 1) {
            $entityFilter = $entityFilter[0];
        } else {
            $entityFilter['_logic'] = 'OR';
            $entityFilter = [$entityFilter];
        }

        $totalEntityList = model(EntityModel::class)->where($baseFilter)->where($entityFilter)->field($fields)->select();
        $totalEntityList = array_group_by($totalEntityList, 'unique_k');

        $resEntityMap = [];
        foreach ($entityList as $entity) {
            if (!isset($totalEntityList[$entity['unique_k']])) {
                continue;
            }
            $resEntityMap[$entity['id']] = array_column($totalEntityList[$entity['unique_k']], 'id');
        }

        $episodeList = model(EntityModel::class)->where([
            'project_id' => $entityList[0]['project_id'],
            'module_id' => module_by_code('episode')['id'],
            'code' => ["IN", join(",", $episodeCodes)],
        ])->select();

        $episodeCodeIdMap = array_column($episodeList, 'id', 'code');
        $episodeIds = array_values($episodeCodeIdMap);

        //获取
        $childrenStepCategoryMap = ReviewFeedbackService::getInstance()->getDemandOrderChildrenStepCategoryId($reviewFeedback['module_code']);
        //处理环节任务计划交付时间
        $stepCategoryTaskDefaultValueMap = [];
        $stepCategoryIds = [];
        $planMap = [];
        if (!empty($reviewFeedback['json'])) {
            $reviewFeedbackJson = json_decode($reviewFeedback['json'], true);
            $planDeliveryTime = $reviewFeedbackJson['plan_delivery_time'] ?? [];
            if (!empty($planDeliveryTime)) {
                foreach ($planDeliveryTime as $planEpisodeId => $planDeliveryTimeData) {
                    foreach ($planDeliveryTimeData as $planStepCategoryId => $planDeliveryTimeItem) {
                        //获取到子级环节Id
                        foreach ($childrenStepCategoryMap[$planStepCategoryId] ?? [] as $childrenStepCategoryId) {
                            $stepCategoryIds[$childrenStepCategoryId] = $childrenStepCategoryId;
                            $stepCategoryTaskDefaultValueMap[$planEpisodeId][$childrenStepCategoryId] = [
                                'plan_delivery_time' => $planDeliveryTimeItem,
                                'plan_end_time' => $planDeliveryTimeItem,
                            ];
                        }
                    }
                }
                $stepCategoryIds = array_values($stepCategoryIds);
                $planMap = PlanService::getInstance()->getStepCategoryPlanData([
                    'plan.project_id' => $entityList[0]['project_id'],
                    'plan.entity_id' => ["IN", $episodeIds],
                    's_tag.link_id' => ["IN", $stepCategoryIds],
                ]);
            }
        }

        return [
            $stepCategoryTaskDefaultValueMap, $stepCategoryIds, $planMap, $resEntityMap, $childrenStepCategoryMap, $episodeCodeIdMap,
        ];
    }

    /**
     * 保存反馈下游返修状态
     * @param int $noteEntityRelationId
     * @param string $status
     * @return array|bool
     * @throws Exception
     */
    public function saveNoteDownstreamRepairStatus(int $noteEntityRelationId, string $status)
    {
        $noteEntityRelation = model(NoteEntityRelationModel::class)->find($noteEntityRelationId);
        if (empty($noteEntityRelation)) {
            throw new LogicException('note entity relation not found', ErrorCode::NOTE_ENTITY_RELATION_NOT_FIND);
        }
        if ($noteEntityRelation['from_upstream_step_category_id'] <= 0) {
            throw new LogicException('data invalid', ErrorCode::DATA_INVALID);
        }
        return CommonService::instance('note_entity_relation')
            ->update([
                'id' => $noteEntityRelationId,
                'repair_accept_status' => $status,
            ], 'note_entity_relation');
    }

    /**
     * 实体是否发生变化
     * @param array $entityDataHandled
     * @param array $entity
     * @return bool
     */
    private function entityChanged(array $entityDataHandled, array $entity)
    {
        foreach (array_intersect_key($entityDataHandled, $entity) as $key => $v) {
            if ($entityDataHandled[$key] != $entity[$key]) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否不存在需求
     * @param       $item
     * @param array $noteKeys
     * @return bool
     */
    private function emptyNote($item, array $noteKeys)
    {
        foreach ($noteKeys as $noteKey) {
            if (!empty($item[$noteKey])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断实体启用废除状态是否发生变化
     * @param $item
     * @param $entity
     * @return bool
     */
    private function reviewEntityEnableNotChanged($item, $entity)
    {
        $moduleCode = module_by_id($entity['module_id'])['code'];
        if (empty($item['enable']) || $item['enable'] === ReviewFeedbackEntityModel::ENABLE_DEFAULT) {
            return true;
        }
        $entityStatus = $entity[$moduleCode . '_status'] ?? null;
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        $entityDisabled = $entityStatus == $closedStatus['id'];
        $reviewFeedbackEntityIsDisable = $item['enable'] === ReviewFeedbackEntityModel::ENABLE_NO;
        if ($reviewFeedbackEntityIsDisable === $entityDisabled) {
            return true;
        }
        return false;
    }

    /**
     * 获取需求的提出人
     * @return array
     * @throws \Exception
     */
    private function getDemandProposer($list, $showSecondLevelStepCategoryList)
    {
        $userFilter = [];
        foreach ($list as $item) {
            foreach ($showSecondLevelStepCategoryList as $showSecondLevelStepCategoryItem) {
                if (!isset($item[$showSecondLevelStepCategoryItem['code']])) {
                    continue;
                }
                $stepCategoryNoteList = $item[$showSecondLevelStepCategoryItem['code']];
                foreach ($stepCategoryNoteList as $stepCategoryNote) {
                    if (!empty($stepCategoryNote['proposer']) && !empty($stepCategoryNote['proposer_department'])) {
                        $userFilter[] = [
                            'user.name' => $stepCategoryNote['proposer'],
                            'department.name' => $stepCategoryNote['proposer_department'],
                        ];
                    }
                }
            }
        }

        $userMap = [];
        if (!empty($userFilter)) {
            $userFilter["_logic"] = "-or";
            $userFilter = [$userFilter];
            $param['filter'] = ["tenant_user.tenant_id" => request()->getTenantId(), $userFilter];
            $param['fields'] = 'user.id,user.name,tenant_user.tenant_id,tenant_user.status,department.id,department.name';
            $remoteUserData = teamones_request('teamones-im', 'tenant_user/select_tenant_user', ["param" => $param])['data'];
            if (!empty($remoteUserData)) {
                $userIds = [];
                foreach ($remoteUserData['rows'] as $user) {
                    $userIds[] = $user['user']['id'];
                }

                $userList = model(UserModel::class)->where(['union_id' => ["IN", $userIds]])->field("union_id,id")->select();
                $saasUserMap = array_column($userList, 'id', 'union_id');

                foreach ($remoteUserData['rows'] as $user) {
                    $user['user']['saas_id'] = $saasUserMap[$user['user']['id']];
                    $userMap[$user['user']['name'] . "_" . $user['department']['name']] = $user;
                }
            }
        }

        return $userMap;
    }

    /**
     * 处理需求单实体任务列表
     * @param $entityTaskList
     * @param $childrenStepCategoryParentMap
     * @return array
     */
    public function dealDemandOrderEntityTaskList($entityTaskList, $childrenStepCategoryParentMap)
    {
        $result = [];
        foreach ($entityTaskList as $entityTaskItem) {
            $parentStepCategoryId = $childrenStepCategoryParentMap[$entityTaskItem['step_category_id']] ?? $entityTaskItem['step_category_id'];
            $result[$entityTaskItem['entity_id'] . '#' . $parentStepCategoryId][] = $entityTaskItem;
        }

        return $result;
    }

    /**
     * 合并实体和环节的计划交付时间
     * @param $episodeId
     * @param $stepCategoryTaskDefaultValueMap
     * @param $reviewFeedbackEntityPlanDeliveryTime
     * @return array|mixed
     */
    public function mergeEntityAndStepCategoryPlanDeliveryTime($episodeId, $stepCategoryTaskDefaultValueMap, $reviewFeedbackEntityPlanDeliveryTime)
    {
        if (empty($episodeId)) {
            return $stepCategoryTaskDefaultValueMap;
        }

        foreach ($reviewFeedbackEntityPlanDeliveryTime as $stepCategoryId => $time) {
            $stepCategoryTaskDefaultValueMap[$episodeId][$stepCategoryId] = [
                'plan_delivery_time' => $time,
                'plan_end_time' => $time,
            ];
        }
        return $stepCategoryTaskDefaultValueMap;
    }

    /**
     * 获取属性默认值
     * @param $stepCategoryIds
     * @return array
     */
    public function getDemandOrderStepCategoryDefaultValue($stepCategoryIds)
    {
        $result = OptionsService::getInstance()->getOptionsData("demand_order_entity_default_attribute_value");

        $stepCategoryMap = [];
        foreach ($result as $stepCategoryId => $resultItem) {
            if (in_array($stepCategoryId, $stepCategoryIds)) {
                $stepCategoryMap[$stepCategoryId] = $resultItem;
            }
        }

        return $stepCategoryMap;
    }

    /**
     * 获取默认值sql
     * @param $stepCategoryIds
     * @return array
     */
    public function getDemandOrderStepCategoryDefaultValueSql($stepCategoryIds)
    {
        $sql = [];
        if (empty($stepCategoryIds)) {
            return $sql;
        }

        $stepCategoryDefaultValueMap = $this->getDemandOrderStepCategoryDefaultValue($stepCategoryIds);

        foreach ($stepCategoryDefaultValueMap as $stepCategoryId => $item) {
            $defaultValue = $item['default'];
            $attribute = $item['attribute'];
            $sql[] = [
                'task.step_category_id' => $stepCategoryId,
                '_string' => "(JSON_UNQUOTE(JSON_EXTRACT(rfe.json, '$.{$attribute}')) <> '$defaultValue' or JSON_UNQUOTE(JSON_EXTRACT(rfe.json, '$.{$attribute}')) is null ) ",
            ];
        }

        if (count($sql) > 1) {
            $sql['_logic'] = "OR";
            $sql = [$sql];
        }

        return $sql;
    }

    /**
     * 获取需求单 新增/返修列表
     * @param $param
     * @return array
     */
    public function getDemandOrderListThumbnail($param): array
    {
        $dbParam = query_array_construct([
            "filter" => "",
            "field" => "strval",
            "page" => "split_array|array_map,intval",
        ], $param['param'] ?? [], [
            "filter" => [],
            "field" => "review_feedback.id id,task.id task_id,task.project_id,rfe.initial_episode_code,task.name,task.plan_start_time,task.plan_end_time",
            "page" => [1, C('default_page_total')],
        ]);
        $param = query_array_construct([
            "project_id" => "intval",
            "department_id" => "intval",
            "episode_code" => "split_array",
            "step_category_id" => "split_array|array_map,intval",
            "start_time" => "intval",
            "end_time" => "intval",
        ], $param);
        $param = array_merge($param, $dbParam);
        if (!empty($param['project_id'])) {
            $param['project_id'] = ProjectService::getInstance()->getProjectParentProjectId($param['project_id']);
        }
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus()['id'];
        $demandOrderList = $this->getDemandOrderListThumbnailDbr($param, true)
            ->field([
                "review_feedback.id id", "task.project_id",
                "rfe.initial_episode_code",
                "episode.id as episode_id",
                "task.step_category_id",
                "count(distinct if(note.demand_type = 'review_feedback', review_feedback.id, null)) as repair_count",
                "count(distinct if(task.step_type = 'step' and JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) <> $closedStatus, review_feedback.id, null)) as append_count",
                "min(if(task.plan_start_time <> 0, task.plan_start_time, null)) start_time",
                "max(if(task.plan_end_time <> 0, task.plan_end_time, null)) end_time",
            ])->group('review_feedback.id, rfe.initial_episode_code, task.step_category_id')
//            ->page(...$param['page'])
            ->select();
        $stepCategoryShowList = TemplateService::getInstance()->findStepCategoryShowList();
        $stepCategoryGroup = [];
        $stepCategoryGroupMap = [];
        foreach ($stepCategoryShowList as $stepCategoryItem) {
            $stepCategoryGroup[$stepCategoryItem['show_name']][] = $stepCategoryItem['id'];
        }
        foreach ($stepCategoryGroup as $showName => $stepCategoryIds) {
            sort($stepCategoryIds);
            foreach ($stepCategoryIds as $id) {
                $stepCategoryGroupMap[$id] = [
                    'id' => $showName,
                    'name' => $showName,
                    'children_ids' => $stepCategoryIds,
                ];
            }
        }
        $res = [];
        foreach ($demandOrderList as $demandOrderItem) {
            if (!isset($stepCategoryGroupMap[$demandOrderItem['step_category_id']])) {
                continue;
            }
            if ((!empty($demandOrderItem['append_count']) || !empty($demandOrderItem['repair_count']))
                && !empty($demandOrderItem['start_time']) && !empty($demandOrderItem['end_time'])) {

                $stepCategory = $stepCategoryGroupMap[$demandOrderItem['step_category_id']] ?? [];
                $stepCategoryIds = $stepCategory['children_ids'] ?? [];
                array_unshift($stepCategoryIds, "ep_" . $demandOrderItem['episode_id'], "id_" . $demandOrderItem['id']);
                $stepCategoryKey = implode('#', $stepCategoryIds);
                if (!isset($res[$stepCategoryKey])) {
                    $demandOrderItem['step_category'] = $stepCategory;
                    $demandOrderItem['step_category_id'] = [$demandOrderItem['step_category_id']];
                    $res[$stepCategoryKey] = $demandOrderItem;
                } else {
                    if (!in_array($demandOrderItem['step_category_id'], $res[$stepCategoryKey]['step_category_id'])) {
                        $res[$stepCategoryKey]['step_category_id'][] = $demandOrderItem['step_category_id'];
                    }
                    $res[$stepCategoryKey]['start_time'] = min($res[$stepCategoryKey]['start_time'], $demandOrderItem['start_time']);
                    $res[$stepCategoryKey]['end_time'] = max($res[$stepCategoryKey]['end_time'], $demandOrderItem['end_time']);
                    $res[$stepCategoryKey]['repair_count'] += $demandOrderItem['repair_count'];
                    $res[$stepCategoryKey]['append_count'] += $demandOrderItem['append_count'];
                }
            }
        }
        return result_array_construct([
            '_final' => 'array_values',
            'id' => 'intval',
            'project_id' => 'intval',
            'episode_id' => 'intval',
            'step_category_id' => 'split_array|array_map,intval|array_filter|array_unique',
            'step_category' => '',
            'initial_episode_code' => '',
            'append_count' => 'intval',
            'repair_count' => 'intval',
            'start_time' => 'intval',
            'end_time' => 'intval',
        ], $res);
    }

    /**
     * 获取需求单dbr
     * @param $param
     * @return array|object|Model|RelationModel
     */
    private function getDemandOrderListThumbnailDbr($param, $withRemake = false)
    {
        $entityModuleId = module_by_code('episode')['id'];
        $dbr = model(ReviewFeedbackModel::class)
            ->join('review_feedback_entity as rfe on review_feedback.id = rfe.review_feedback_id')
            ->join('entity on entity.id = rfe.entity_id', 'left')
            ->join('task on entity.id = task.source_entity_id', 'left')
            ->join('(select id,code,project_id from entity where module_id = ' . $entityModuleId . ' ) as episode on episode.code = entity.initial_episode_code and episode.project_id = entity.project_id');
        if ($withRemake) {
            $dbr = $dbr
                ->join('note_entity_relation on rfe.review_feedback_id = note_entity_relation.review_feedback_id and rfe.entity_id = note_entity_relation.entity_id and note_entity_relation.relation_type = "step_category"')
                ->join('note on note.id = note_entity_relation.note_id')
                ->join('repair_order_affected_task roat on roat.task_repair_order_id = note.task_repair_order_id');
        }
        // 项目
        if (!empty($param['project_id'])) {
            $dbr = $dbr->where(['entity.project_id' => $param['project_id'],
                'task.project_id' => $param['project_id']]);
        }
        // 剧集
        if (!empty($param['episode_code'])) {
            $dbr = $dbr->where(['entity.initial_episode_code' => ['IN', $param['episode_code']]]);
        }
        // 环节筛选
        if (!empty($param['step_category_id'])) {
            $dbr = $dbr->where(['task.step_category_id' => ['IN', $param['step_category_id']]]);
        }
        // 部门筛选
        if (!empty($param['department_id'])) {
            $departmentUserData = TenantService::getInstance()->selectDepartmentUser(request()->getTenantId(), [
                'param' => ['filter' => ['department_id' => $param['department_id'],]]
            ]);
            $saasUserIdList = array_column($departmentUserData['rows'], 'saas_user_id');
            if (empty($saasUserIdList)) {
                return $dbr->where("1 = 0");
            }
            $dbr = $dbr->join('task_member on task.id = task_member.task_id', 'left')
                ->where(['task_member.partner' => ['IN', $saasUserIdList]]);
        }
//        // 个人
//        if (empty($param['step_category_id']) && empty($param['department_id'])) {
//            $dbr = $dbr->join('task_member on task.id = task_member.task_id', 'left')
//                ->where(['task_member.partner' => request()->getUserId()]);
//        }
        if (!empty($param['start_time'] && !empty($param['end_time']))) {
            $dbr = $dbr->where([
                'rfe.published' => 'yes',
                'rfe.published_time' => ['BETWEEN', [$param['start_time'], $param['end_time']]],
            ]);
        }
        return $dbr;
    }

    /**
     * 镜头特效方式处理逻辑
     * @param $originalSpecialEffect
     * @param $newSpecialEffect
     * @return String
     */
    private function handleComplexShotSpecialEffect($originalSpecialEffect, $newSpecialEffect)
    {
        if (!in_array($newSpecialEffect, ['引擎特效', '其他特效', '混合特效', '无特效'])) {
            return $originalSpecialEffect;
        }

        if ($originalSpecialEffect == '引擎特效' && $newSpecialEffect == '其他特效') {
            return '混合特效';
        } elseif ($originalSpecialEffect == '其他特效' && $newSpecialEffect == '引擎特效') {
            return '混合特效';
        } elseif ($originalSpecialEffect == '混合特效') {
            return '混合特效';
        } elseif ($originalSpecialEffect == '无特效') {
            return $newSpecialEffect;
        } else {
            return $newSpecialEffect;
        }
    }

    /**
     * 获取当前集所有走完的标准新增的阶段id
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param $moduleCode [模块code]
     * @param $outOfRangeReviewFeedbackIds [需要排除的需求单id]
     * @return array
     */
    public function getStandardAppendStageIdsByEpisodeCode($projectId, $episodeCode, $moduleCode, $outOfRangeReviewFeedbackIds = [])
    {
        $res = [
            'standard_append_stage_ids' => [],
            'not_standard_append_stage_ids' => []
        ];

        $where = [
            'project_id' => $projectId,
            'current_episode_codes' => $episodeCode,
            // 新增标识，当出现有这个标识，说明是新增需求单更新最新逻辑。如果没有这个标识，所有阶段都可以选则，否则只能选择排最前的阶段
            "json ->> '$.append_mark'" => self::APPEND_MARK,
            'demand_type' => ReviewFeedbackModel::DEMAND_TYPE_DEMAND_ORDER,
            'standard_append' => ['IN', [ReviewFeedbackModel::STANDARD_APPEND_YES, ReviewFeedbackModel::STANDARD_APPEND_NO]],
            'module_code' => $moduleCode
        ];

        // 过滤需要排除的需求单id
        if (!empty($outOfRangeReviewFeedbackIds)) {
            $where['id'] = ['NOT IN', $outOfRangeReviewFeedbackIds];
        }

        $list = model(ReviewFeedbackModel::class)->field(['stage_id', 'standard_append'])
            ->where($where)
            ->select();

        if (empty($list)) {
            return $res;
        }

        foreach ($list as $item) {
            if ($item['standard_append'] == ReviewFeedbackModel::STANDARD_APPEND_YES) {
                $res['standard_append_stage_ids'][] = $item['stage_id'];
            } else {
                $res['not_standard_append_stage_ids'][] = $item['stage_id'];
            }
        }

        return $res;
    }

    /**
     * 获取当前阶段(存在标准新增需求的阶段)
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param array $outOfRangeReviewFeedbackIds [需要排除的需求单id]
     * @return array|false|mixed|string|null
     */
    public function getCurrentStage($projectId, $episodeCode, $moduleCode, $outOfRangeReviewFeedbackIds = [])
    {
        $where = [
            'project_id' => $projectId,
            'current_episode_codes' => $episodeCode,
            // 新增标识，当出现有这个标识，说明是新增需求单更新最新逻辑。如果没有这个标识，所有阶段都可以选则，否则只能选择排最前的阶段
            "json ->> '$.append_mark'" => self::APPEND_MARK,
            'demand_type' => ReviewFeedbackModel::DEMAND_TYPE_DEMAND_ORDER,
            'standard_append' => ReviewFeedbackModel::STANDARD_APPEND_YES,
            'module_code' => $moduleCode
        ];

        // 过滤需要排除的需求单id
        if (!empty($outOfRangeReviewFeedbackIds)) {
            $where['id'] = ['NOT IN', $outOfRangeReviewFeedbackIds];
        }

        // 获取集走所有过的阶段
        $stageIds = model(ReviewFeedbackModel::class)->field('stage_id')
            ->where($where)
            ->group('stage_id')
            ->column('stage_id');

        if (empty($stageIds)) {
            return [];
        }

        // 获取最近的一个阶段
        return model(StageModel::class)->field(['id', 'order_number'])
            ->where(['id' => ['IN', $stageIds]])
            ->order('order_number DESC')
            ->find();
    }

    /**
     * 组装新增类型
     * 提出阶段选择规则
     * 1. 提出阶段按顺序升序排序，只能从最靠前开始选择(标准新增需遵守，非标准新增不受限制)
     * 2. 同一个项目，同一个集数，在同一个阶段中，需要匹配阶段设置的标准新增次数，如果超过该次数，其余全部为非标准新增类型，如果设置的标准新增次数小于0，需求可设置标准新增和非标准新增
     * 3. 示例，在神印王座、EP001集中，提出阶段排序如下
     *    剧本围读会、创意需求会、美术确认会、分镜讲戏
     *    此时每个阶段都是标准新增
     *    各环节规则如下
     *    剧本围读会：只能下发一次标准需求
     *    创意需求会：只能下发一次标准需求
     *    美术确认会：能下发多次标准需求，美术交付阶段完成后，属于非标
     *    分镜讲戏：能下发多次标准需求
     *
     *    a. 第一个需求单选择“剧本围读会”，新增类型为标准新增，那其他需求单再选择剧本围读会时，新增类型只能是非标准新增；
     *    b. 第二个需求单再次选择“剧本围读会”，新增类型只能是非标准新增，其他阶段都是标准新增；
     *    c. 第三个需求单选择“创意需求会”，新增类型为标准新增；
     *    e. 第四个需求单，此时EP001集的最新阶段为 “创意需求会”，不能选择此阶段之前的阶段标准新增，只能选择它之后的阶段的标准新增，这个需求提出阶段选择“创意需求会”，新增类型为非标准新增，但是可以选择此阶段之前阶段的非标新增；
     *    f. 第五个需求单，选择“美术确认会”，新增类型为标准新增，如果美术交付阶段未完成(查该工序下任务是否完成)，下一个需求单依然可以选择“美术确认会”的标准新增，如果美术交付阶段已完成，那下一个需求单依然可以选择“美术确认会”的非标准新增
     *    g. 第六个需求单，此时 “分镜讲戏” 之前的阶段都无法选中标准新增需求，因为“分镜讲戏”能下发多次标准需求，所以不限制
     * 4. 当需求单未发布并且被删除了，那相当于把阶段释放。比如新增一个需求单，阶段为 “创意需求会”，新增类型为标准新增，添加成功后，未发布需求，把这个需求单删除，再次添加一个需求单， 阶段为 “创意需求会”，此时新增类型还是标准新增
     * @param $data
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param $stageId [阶段id]
     * @param $reviewFeedbackId [需求id，修改需求单时，需要传需求id，特殊处理]
     */
    private function buildStageAndStandardAppend(&$data, $projectId, $episodeCode, $stageId, $reviewFeedbackId = 0)
    {
        unset($data['stage_name']);
        // 组装需要排除的需求单id，修改需求单不需要把该需求单加入阶段的校验
        $rangeReviewFeedbackIds = empty($reviewFeedbackId) ? [] : [$reviewFeedbackId];
        if (!empty($reviewFeedbackId)) {
            $reviewFeedbackInfo = model(ReviewFeedbackModel::class)->field(['id', 'stage_id', 'standard_append'])->where(['id' => $reviewFeedbackId])->find();
        }

        // 1. 如果不是修改需求单，需要校验提出阶段。
        // 2. 如果是修改需求，并且更新了提出阶段，必须校验提出阶段的合法性
        // 3. 如果是修改需求，没有更新提出阶段，那不需要更新
        if (empty($rangeReviewFeedbackIds) || !empty($reviewFeedbackInfo) && $reviewFeedbackInfo['stage_id'] != $stageId) {
            $stageInfo = model(StageModel::class)->field([
                'id',
                'name',
                'order_number',
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.standard_append_number')) as standard_append_number",
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.join_demand_stage_rule')) as join_demand_stage_rule",
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.task_step_id')) as task_step_id"
            ])->where(['id' => $stageId])->find();

            if (empty($stageInfo)) {
                throw new LogicException('Stage not found.', ErrorCode::STAGE_NOT_FOUND);
            }

            // 创建的需求是标准新增需求，并且设置了参加阶段规则校验，需要进行阶段规则校验
            if ($data['standard_append'] == ReviewFeedbackModel::STANDARD_APPEND_YES && $stageInfo['join_demand_stage_rule'] == StageModel::JOIN_DEMAND_STAGE_RULE_YES) {
                $this->checkStageRule($projectId, $episodeCode, $data['module_code'], $stageInfo, $rangeReviewFeedbackIds);
            }

            $data['stage_name'] = $stageInfo['name'];
            // 标识需求单需要校验提出阶段规则
            $data['json']['append_mark'] = self::APPEND_MARK;
        }
    }

    /**
     * 校验当前集数在指定阶段是否已添加过标准新增
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param $moduleCode [模块code]
     * @param $stageId [阶段id]
     * @param $outOfRangeReviewFeedbackIds [需要排除的需求单id]
     */
    public function getStandardAppendCountByEpisodeStage($projectId, $episodeCode, $moduleCode, $stageId, $outOfRangeReviewFeedbackIds = [])
    {
        $where = [
            'project_id' => $projectId,
            'current_episode_codes' => $episodeCode,
            // 新增标识，当出现有这个标识，说明是新增需求单更新最新逻辑。如果没有这个标识，所有阶段都可以选则，否则只能选择排最前的阶段
            "json ->> '$.append_mark'" => self::APPEND_MARK,
            'demand_type' => ReviewFeedbackModel::DEMAND_TYPE_DEMAND_ORDER,
            'module_code' => $moduleCode,
            'stage_id' => $stageId,
            'standard_append' => ReviewFeedbackModel::STANDARD_APPEND_YES
        ];

        // 过滤需要排除的需求单id
        if (!empty($outOfRangeReviewFeedbackIds)) {
            $where['id'] = ['NOT IN', $outOfRangeReviewFeedbackIds];
        }

        return model(ReviewFeedbackModel::class)->field('id')
            ->where($where)
            ->count();
    }

    /**
     * 校验阶段规则
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param $moduleCode [模块code]
     * @param $stageInfo [阶段信息  {"id": 阶段id, "name": 阶段名称, "order_number": 排序, "standard_append_number": 标准新增的限制次数, "join_demand_stage_rule": 是否加入校验规则, "task_step_id": 需要校验该工序下的任务工序id}]
     * @param $rangeReviewFeedbackIds [修改的需求单id]
     */
    public function checkStageRule($projectId, $episodeCode, $moduleCode, $stageInfo, $rangeReviewFeedbackIds)
    {
        // 获取当前集已经到的最新阶段信息(标准新增)
        $currentStageInfo = $this->getCurrentStage($projectId, $episodeCode, $moduleCode, $rangeReviewFeedbackIds);

        // 1. 当前有最新阶段，并且当前选择的阶段小于最新阶段，不允许选择最新阶段之前的阶段标准需求（只能选择非标准新增）
        if (!empty($currentStageInfo) && $stageInfo['order_number'] < $currentStageInfo['order_number']) {
            throw new LogicException('Cannot be less than the latest stage.', ErrorCode::CANNOT_LESS_THAN_LATEST_STAGE);
        }

        // 获取该工序下未完成的任务
        $notFinalTaskStepGroup = $this->getNotFinalTaskStepMap($projectId, $episodeCode, [$stageInfo['task_step_id']]);

        // 2. 设置过工序id判断条件 && 该工序下有任务 && 有未完成的任务  该阶段只能添加非标准需求
        if (
            // 设置过工序id判断条件
            !empty($stageInfo['task_step_id']) &&
            // 该工序下有任务
            isset($notFinalTaskStepGroup[$stageInfo['task_step_id']]) &&
            // 有未完成的任务
            empty($notFinalTaskStepGroup[$stageInfo['task_step_id']])
        ) {
            throw new LogicException('Not allowed to submit standard append.', ErrorCode::CANNOT_LESS_THAN_LATEST_STAGE);
        }

        // 3. 标准新增的次数大于0，需要校验
        if ($stageInfo['standard_append_number'] > 0) {
            // 获取当前选中阶段的标准新增类型，如果不是修改需求单，或者修改需求单的阶段，需要重新获取新增类型
            $standardAppendCount = $this->getStandardAppendCountByEpisodeStage($projectId, $episodeCode, $moduleCode, $stageInfo['id'], $rangeReviewFeedbackIds);

            // 如果提交的是标准新增，并且提交次数已超过设置标准新增限制的次数，那就不允许再提交标准新增，只能提交非标准新增需求单
            if ($standardAppendCount >= $stageInfo['standard_append_number']) {
                throw new LogicException('The number of submissions exceeds the range.', ErrorCode::CANNOT_LESS_THAN_LATEST_STAGE);
            }
        }
    }

    /**
     * 获取未完成的任务，根据工序id进行分组
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param $stepIds [工序id]
     * @return array {'工序id': [任务id合集]}
     */
    public function getNotFinalTaskStepMap($projectId, $episodeCode, $stepIds)
    {
        if (empty($stepIds)) {
            return [];
        }

        // 获取已完成状态id
        $finalStatusId = StatusService::getInstance()->byCode('final')['id'];
        // 获取集数的模块id
        $episodeModuleId = Module::$moduleDictData['module_index_by_code']['episode']['id'];
        // 获取集数信息
        $episodeInfo = model(EntityModel::class)->field(['id'])->where(['project_id' => $projectId, 'code' => $episodeCode, 'module_id' => $episodeModuleId])->find();

        if (empty($episodeInfo)) {
            throw new LogicException('Episode is not found.', ErrorCode::ENTITY_NOT_FOUND);
        }

        // 获取任务信息，需要根据项目、集数、工序获取任务，集数和标准任务关联关系在task_relation_tag表
        $taskList = model(TaskModel::class)
            ->field([
                'task.id',
                'task.step_id',
                "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status')) as task_status"
            ])
            ->join('task_relation_tag as t_r_t on t_r_t.task_id = task.id', 'left')
            ->where([
                'task.project_id' => $projectId,
                'task.step_id' => ['IN', $stepIds],
                'task.step_type' => TaskModel::STEP_TYPE_TO_DO,
                't_r_t.link_module_code' => 'episode',
                't_r_t.link_id' => $episodeInfo['id']
            ])
            ->select();

        $taskList = array_group_by($taskList, 'step_id');

        // 根据工序id进行分组
        $notFinalTaskStepGroup = [];
        foreach ($taskList as $stepId => $item) {
            $notFinalTaskStepGroup[$stepId] = $this->dealNotFinalTask($item, $finalStatusId);
        }

        return $notFinalTaskStepGroup;
    }

    /**
     * 组装未完成任务数据
     * @param $taskList [任务列表 {"id": 任务id, "step_id": 工序id, "task_status": 任务状态}]
     * @param $finalStatusId [已完成状态id]
     * @return array 任务id合集
     */
    private function dealNotFinalTask($taskList, $finalStatusId)
    {
        $notFinalTask = [];
        foreach ($taskList as $item) {
            if ($item['task_status'] != $finalStatusId) {
                $notFinalTask[] = $item['id'];
            }
        }

        return $notFinalTask;
    }

    /**
     * 关闭需求单
     * @param int $reviewFeedbackId 需求单ID
     * @return array|bool
     */
    public function closeDemandOrder(int $reviewFeedbackId)
    {
        //判断需求是否存在
        $info = model(ReviewFeedbackModel::class)->field('id')->where(['id' => $reviewFeedbackId])->find();
        if (empty($info)) {
            throw new LogicException('需求单不存在', ErrorCode::REVIEW_FEEDBACK_NOT_FOUND);
        }

        //检查是否还存在 未发布的需求和实体
        $pf = $this->isAllPublished($reviewFeedbackId);
        if (!$pf) {
            throw new LogicException('有实体未发布，请核对', ErrorCode::ENTITY_HAVE_NOT_PUBLISHED);
        }

        //关闭需求单
        return model(ReviewFeedbackModel::class)->modifyItem(['id' => $info['id'], 'status' => ReviewFeedbackModel::STATUS_FINAL]);
    }
}
